I have an entity service on which I need to filter a collection of child entity, based on a list of id's. My service have a public method which receive the id of the parent entity and a list of id's of some of his children entities.
By default, I know that JPA will fetch all related entities and this his the actual behavior. But we need to work on the performance of the service. So instead of getting all related entities and filter them with many loop (filter on id's and also on other properties like date property), I want to get only entities concerned by my request.
My Parent entity
@Entity
@Table(name = "MyParent")
public class MyParentEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "SEQ_MyParent")
@SequenceGenerator(allocationSize = 1, name = "SEQ_MyParent",
sequenceName = "SEQ_MyParent")
@Column(name = "ID_PARENT")
private Long id;
@OneToMany(mappedBy = "myParent", cascade = CascadeType.ALL,
fetch = FetchType.EAGER, orphanRemoval = true)
private final List<MyChildEntity> myChild = new ArrayList<MyChildEntity>();
}
My Child Entity
@Entity
@Table(name = "MyChild")
public class MyChildEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "SEQ_MyChild")
@SequenceGenerator(allocationSize = 1, name = "SEQ_MyChild",
sequenceName = "SEQ_MyChild")
@Column(name = "ID_CHILD")
private Long id;
@ManyToOne
@JoinColumn(name = "ID_PARENT")
private MyParentEntity myParent;
}
I'm using Spring-data CrudRepository to get data from my DB and I also extends JpaSpecificationExecutor to use Predicate.
public interface MyParentRepository extends CrudRepository<MyParentEntity, Long>,
JpaSpecificationExecutor<MyParentEntity> {
}
This let me use CrudRepository findOne() method but with a Specification object instead of the regular Long parameter.
Also, I combine multiples Specification's object with the following call:
this.myParentRepository.findOne(Specifications
.where(firstSpecification(parentId))
.and(secondSpecification(childrenIdsList)));
I created a simple junit test with one Parent linked to two children entities. In my request, I'm able to get the parent entity with the provided Id. But even if I provide the child id, I always get both children entities in the list inside the parent.
In my method which return a new Specification object, in which the toPredicate method is override, I'm unable to create a Predicate that will filter my children collection and only get those one I'm interested. I know that the Hibernate Criteria has the possibility to add "Restrictions" but this is not available in the CriteriaBuilder that is provided with the toPredicate method.
public static Specification<MyParentEntite> firstSpecification(final Long id) {
return new Specification<MyParentEntite>() {
@Override
public Predicate toPredicate(Root<MyParentEntite> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate predicate = cb.equal(root.get(MyParentEntity_.id), id);
return cb.and(predicate);
}
};
}
public static Specification<MyParentEntite> secondSpecification(final List<Long> ids) {
return new Specification<MyParentEntite>() {
@Override
public Predicate toPredicate(Root<MyParentEntite> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
Root<MyChildEntity> child = query.from(MyChildEntity.class);
Expression<Long> exp = child.get(MyChildEntity_.id);
Predicate p = exp.in(ids);
return cb.and(p);
}
};
}
In the secondSpecification() method, I also tried to use ListJoin instead of Root directly in the Entity. I searched in other questions here but it seems that this concern is solved with the Hibernate Criteria restrictions or with a LeftJoin, which I tried in my ListJoin in specifing JoinType.LEFT parameter.
Here are links to already tested solutions whitout success :
JPA CriteriaBuilder - How to use "IN" comparison operator
JPA2 Criteria-API: select... in (select from where)
I want to mention that I'm relatively new with Criteria API and Predicate. Maybe I'm missing something that is simple but that is obvious to experienced JPA developpers!
Thanks a lot for your help!
See Question&Answers more detail:
os