问题
In my current project I'm using Spring Data JPA and I have more than 20 @Entity
classes.
I want to create repositories for them, but creating another classes, each for any model, with @Repository
annotation seems to be some kind of overkill and a lot of "repeated" code - all repository classes will look like:
@Repository
public interface SomeModelRepository extends CrudRepository<SomeModel, Long> {
}
There is any way to create "automagically" those repositories? And specify only those that I will extend with my own methods? How should be that done in DRY and KISS way?
回答1:
As mentioned in comments above (in question) - no, I have to create repository for every entity I need. Also it is worth to think about aggregate roots (if some entities won't be queried directly).
回答2:
When I worked with a datasource with about 100+ entities I used the following method so that do not create repositories for each entity. I worked mainly for only saving information from the source to our database. However have some idea how to retrieve data also.
The main idea to create @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;
}
}
Then extends all other entities:
@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 + '\'' +
'}';
}
}
Your repository in this case will be:
public interface SuperRepository extends JpaRepository<SuperClass, Integer> {
}
And you can apply it:
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 will create Class1 and Class2 tables and fill them with data.
The next step - how to retrieve the data. I would think about such method - create queries for each class in this one repository:
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();
}
Then when you apply this:
System.out.println(superRepository.findAllClass1());
System.out.println(superRepository.findAllClass2());
you will get:
[Class1{classInfo='Class1 info'}]
[Class2{classInfo='Class2 info'}]
回答3:
For people who land here looking for ways to avoid too many repository interface files. There is a thing called 'Composable Repositories' in Spring as of 5.0 and there are quite a few sample codes available so am not going to re-explain that here. I found a similar way to avoid too many files as below: Create a normal class which becomes the supplier of all those empty repository interfaces. Define the @Repository interfaces as non-public interfaces within that containing class and write getters for each of those repositories. Sample below:
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>{}
Put all this is in a single java file. And make sure its in path of repository scans for your project.
来源:https://stackoverflow.com/questions/35201546/spring-data-jpa-multiple-repositories-without-many-classes