Reputation: 2040
I have several entities and use Spring Data JPA repositories with specifications query my database. Therefore I created a generic class SpecBuilder
to build my queries based on a query description (MyQueryDescriptor
).
public class Specs {
public static <T extends MyEntityIFace> Specification<T> myfind(final MyQueryDescriptor qDesc) {
return new Specification<T>() {
@Override
public Predicate toPredicate(Root<T> root,
CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
try {
return SpecBuilder.mySpec(root, criteriaQuery, criteriaBuilder, qDesc);
} catch (Exception e) {
...handle error...
}
}
};
}
}
My repositories:
public interface Entity1DAO extends Repository<Entity1,Long>,
JpaSpecificationExecutor {
}
and
public interface Entity2DAO extends Repository<Entity2,Long>,
JpaSpecificationExecutor {
}
Now there are 3 things I am not quite sure about:
1)
Is this use of a generic SpecBuilder a clean design?
2)
Is there a way to avoid writing those repository interfaces for each entity? Let's say a generic repository?
3)
The MyQueryDescriptor
class has a method to return an instance of an Entity, which will be queried.
What would be a clean way to obtain the according repository based on the entity class, avoiding a switch case? I was thinking about putting an annotation with the specific repository class to each entity but it feels a bit smelly.
Should I create a factory and inject a map like
Entity1.class => Entity1DAO
Entity2.class => Entity2DAO
?
Upvotes: 7
Views: 20355
Reputation: 10716
Is this use of a generic SpecBuilder a clean design?
Depends what criteria you have for clean design. Will the same MyQueryDescriptor
work for different entities? Surely they have different properties, so you need to ask yourself whether a given MyQueryDescriptor
could be mistakenly used for an incompatible entity and ways in which you could prevent it. We cannot comment on that since we don't know how your SpecBuilder
works.
Is there a way to avoid writing those repository interfaces for each entity? Let's say a > generic repository?
Nope. It's not much boilerplate either, though.
- The MyQueryDescriptor class has a method to return an instance of an Entity, which will be queried. What would be a clean way to obtain the according repository based on the entity class, avoiding a switch case?
I suppose you could use getBeanProvider
at runtime, where you would define resolvableType
as CrudRepository<MyEntityType, IdType>
.
However, if I were you, I'd consider switching to using JPA Criteria API without the JpaSpecificationExecutor
abstraction on top of it. That would probably prove to be more natural. The design of Spring repositories is centered around the idea of the repository organizing queries around the given specific entity, whereas your use case seems to go in exactly the opposite direction - to dynamically pick an entity and then find a repository to fit in, just to satisfy Spring's restrictions. You seem to be fighting the framework in that regard.
Upvotes: 0
Reputation: 2931
You can use entity inheritance and use Spring Expression Language (SpEL) to make repository issue calls on right entities. Like in my last update here
Upvotes: 2