【问题标题】:Spring Data (JPA) multiple repositories without many classes没有很多类的 Spring Data (JPA) 多个存储库
【发布时间】:2016-02-04 12:53:37
【问题描述】:

在我当前的项目中,我使用的是 Spring Data JPA,并且我有超过 20 个@Entity 类。

我想为它们创建存储库,但是为任何模型创建另一个类,每个类都使用@Repository 注释似乎是某种矫枉过正和大量“重复”代码 - 所有存储库类看起来像:

@Repository
public interface SomeModelRepository extends CrudRepository<SomeModel, Long> {
}

有什么方法可以“自动”创建这些存储库?并仅指定我将使用自己的方法扩展的那些?应该如何以 DRY 和 KISS 的方式完成?

【问题讨论】:

  • 没有……你需要接口。你也不需要@Repository 它什么也没增加。
  • 一旦您的项目增长并且您需要为您的一个或多个实体添加额外的查询,您会很高兴为每个实体定义一个单独的接口
  • 除此之外 - 您真的需要为每个实体创建一个存储库吗?通常有些实体是所有者/aggregate roots,其余的只是他们的孩子,不会被直接查询。
  • 好的,谢谢您的回复。我会重新考虑是否需要为每个实体创建一个存储库并只创建真正需要的。

标签: java spring jpa spring-data spring-data-jpa


【解决方案1】:

正如上面 cmets 中提到的(有问题) - ,我必须为我需要的每个实体创建存储库。同样值得考虑aggregate roots(如果某些实体不会被直接查询)。

【讨论】:

    【解决方案2】:

    当我使用包含大约 100 多个实体的数据源时,我使用了以下方法,这样就不会为每个实体创建存储库。 我的工作主要是只将信息从源保存到我们的数据库。不过也知道如何检索数据。

    创建@MappedSuperclass的主要思想:

    @MappedSuperclass
    public abstract class SuperClass {
    
        @Id
        @GeneratedValue
        private Integer id;
    
        public SuperClass() {
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    }
    

    然后扩展所有其他实体:

    @Entity
    public class Class1 extends SuperClass {
    
        private String classInfo;
    
        public String getClassInfo() {
            return classInfo;
        }
    
        public void setClassInfo(String classInfo) {
            this.classInfo = classInfo;
        }
    
        @Override
        public String toString() {
            return "\nClass1{" +
                    "classInfo='" + classInfo + '\'' +
                    '}';
        }
    }
    
    @Entity
    public class Class2 extends SuperClass {
    
        private String classInfo;
    
        public String getClassInfo() {
            return classInfo;
        }
    
        public void setClassInfo(String classInfo) {
            this.classInfo = classInfo;
        }
    
        @Override
        public String toString() {
            return "\nClass2{" +
                    "classInfo='" + classInfo + '\'' +
                    '}';
        }
    }
    

    在这种情况下,您的存储库将是:

    public interface SuperRepository extends JpaRepository<SuperClass, Integer> {
    
    }
    

    你可以应用它:

        Class1 class1 = new Class1();
        class1.setClassInfo("Class1 info");
    
        Class2 class2 = new Class2();
        class2.setClassInfo("Class2 info");
    
        superRepository.save(class1);
        superRepository.save(class2);
    
        //OR 
        //List<SuperClass> entities = Arrays.asList(class1,class2);
        //superRepository.saveAll(entities);
    

    Hibernate 将创建 Class1Class2 表并用数据填充它们。

    下一步 - 如何检索数据。 我会考虑这种方法 - 为这个存储库中的每个类创建查询:

    public interface SuperRepository extends JpaRepository<SuperClass, Integer> {
    
        @Query("select c from Class1 c")
        List<Class1> findAllClass1();
    
        @Query("select c from Class2 c")
        List<Class2> findAllClass2();
    
    }
    

    那么当你应用这个时:

        System.out.println(superRepository.findAllClass1());
        System.out.println(superRepository.findAllClass2());
    

    你会得到:

    [Class1{classInfo='Class1 info'}]

    [Class2{classInfo='Class2 info'}]

    【讨论】:

    • 我没有投票,因为它没有按要求回答问题。但我真的很喜欢你建议的方法。我会用那个。
    【解决方案3】:

    适合那些想避免过多存储库接口文件的人。从 5.0 开始,Spring 中有一个叫做“可组合存储库”的东西,并且有很多示例代码可用,所以我不打算在这里重新解释。 我找到了一种类似的方法来避免太多文件,如下所示: 创建一个普通类,它成为所有这些空存储库接口的提供者。将@Repository 接口定义为包含类的非公共接口,并为每个存储库编写getter。示例如下:

    Public MyRepositoryProvider {
    
      @Autowired 
      Class1Repository class1Repo;
      public Class1Repository getClass1Repo() {
          return class1Repo;
    
      //.... similarly for Class2Repo
    
    }
    
    @Repository
    interface Class1Repository extends CRUDRepository<Class1, Long>{}
    @Repository
    interface Class2Repository extends CRUDRepository<Class2, Long>{}
    

    将所有这些都放在一个 java 文件中。并确保它在您项目的存储库扫描路径中。

    【讨论】:

    • 我认为这实际上不起作用,因为接口没有在额外的文件中定义,因此不是公共的。不过,您只能在一个额外的文件中创建一个超类,比如说NestedRepository,所有嵌套的存储库都扩展(而不是 CrudRepository)。 RepositoryProvider 的成员必须是 NestedRepository 类型。因为超级接口是在它自己的文件中定义的,所以具有公共可见性。
    猜你喜欢
    • 1970-01-01
    • 2015-04-07
    • 2019-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-18
    • 2016-03-26
    • 1970-01-01
    相关资源
    最近更新 更多