Ho un servizio di entità su cui ho bisogno di filtrare una raccolta di entità figlio, in base a un elenco di ID. Il mio servizio ha un metodo pubblico che riceve l'id dell'entità padre e un elenco di id di alcune delle sue entità figli.Come filtrare le raccolte di entità figlio con predicato?
Per impostazione predefinita, so che JPA recupera tutte le entità correlate e questo è il suo comportamento effettivo. Ma dobbiamo lavorare sull'esecuzione del servizio. Quindi, invece di ottenere tutte le entità correlate e filtrarle con molti loop (filtro su ID e anche su altre proprietà come la proprietà date), voglio ottenere solo le entità interessate dalla mia richiesta.
miei genitori entità
@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>();
}
mio bambino 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;
}
sto usando CrudRepository Primavera-dati per ottenere i dati dal mio DB e mi si estende anche JpaSpecificationExecutor da usare predicato.
public interface MyParentRepository extends CrudRepository<MyParentEntity, Long>,
JpaSpecificationExecutor<MyParentEntity> {
}
Questo mi ha lasciato usare CrudRepository findOne() metodo, ma con un oggetto specifica al posto del parametro lungo regolare.
Inoltre, combino oggetto multipli di specifica con la seguente chiamata:
this.myParentRepository.findOne(Specifications
.where(firstSpecification(parentId))
.and(secondSpecification(childrenIdsList)));
ho creato un semplice test JUnit con un genitore legato a due entità bambini. Nella mia richiesta, sono in grado di ottenere l'entità padre con l'Id fornito. Ma anche se fornisco l'id del bambino, ottengo sempre entrambe le entità figli nella lista all'interno del genitore.
Nel mio metodo che restituisce un nuovo oggetto Specification, in cui il metodo toPredicate ha precedenza, non sono in grado di creare un predicato che filtrerà la mia raccolta figli e otterrà solo quelli a cui sono interessato. So che Hibernate Criteria ha la possibilità di aggiungere "Restrizioni" ma questo non è disponibile nel CriteriaBuilder fornito con il metodo toPredicate.
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);
}
};
}
Nel metodo secondSpecification(), ho anche cercato di utilizzare ListJoin anziché Root direttamente nell'Entità. Ho cercato in altre domande qui, ma sembra che questa preoccupazione sia risolta con le restrizioni dei Criteri di Hibernate o con un LeftJoin, che ho provato nel mio ListJoin specificando il parametro JoinType.LEFT.
Ecco i link ai già collaudati soluzioni whitout successo:
JPA CriteriaBuilder - How to use "IN" comparison operator
JPA2 Criteria-API: select... in (select from where)
voglio dire che io sono relativamente nuovo con criteri di API e predicato. Forse mi manca qualcosa che è semplice ma è ovvio per gli esperti di sviluppo JPA!
Grazie mille per il vostro aiuto!