Задание критериев для дочерней таблицы в отношениях один ко многим
У меня есть два объекта сущности (A и B), которые имеют отношение "один ко многим". Я использую JPA (Hibernate), чтобы соединить эти таблицы и запросить их для определенного набора результатов, но критерии, которые я определяю для дочерней таблицы (B), не применяются при получении моих результатов. Вот как я определил запрос:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<A> query = builder.createQuery(A.class);
Root<A> a = query.from(A.class);
Join<A, B> abJoined = a.join(A_.b);
query.distinct(true)
.where(builder.and(
builder.equal(a.get(A_.id), id),
builder.equal(a.get(A_.active), 1),
builder.equal(a.get(A_.location), 1011),
builder.equal(a.get(A_.status), "Pending"),
builder.equal(abJoined.get(B_.status), "Not Moved"),
builder.greaterThan(abJoined.get(B_.detailId), 0)
));
Когда я звоню entityManager.createQuery(query).getResultList();
Я получаю один экземпляр объекта "A", но когда я пытаюсь получить доступ к "B" через "A" a.getB()
два критерия, которые я указал для abJoined
не применяются, и я получаю все экземпляры "B", которые соединены с "A". Есть ли что-то еще, что мне нужно сделать, чтобы применить эти критерии? Если критерии не могут быть применены, есть ли рекомендуемый метод для удаления соответствующих экземпляров "B" из набора результатов?
Я могу предоставить больше кода или других деталей, если это необходимо.
2 ответа
Запрос используется для выбора того, какие объекты должны быть возвращены запросом. Но объекты A никогда не будут частичными объектами, содержащими только подмножество их B. Они всегда будут полными экземплярами A, отражающими состояние того, что A находится в базе данных, и с каким B это связано.
Кстати, даже если бы это было возможно (это не так, и явно запрещено спецификацией JPA), ваш запрос должен был бы по крайней мере также загрузить B, используя выборочное соединение. В противном случае запрос возвращает только состояние A, а связанные B загружаются лениво.
Но в JPA для отношения @OneToMany Query запускается первым по мастеру со всеми критериями и выбирает только основные записи. Позже по отдельности выполняется запрос, НО, НО, НО...... критерии таблицы B будут содержать не все условия, а только одно условие, т.е. только первичный ключ VALUE основных записей, извлеченных, т. Е. Только с одним условием "b. A_id = [primarykeyfetched from master] "
SOLUTION - это просто Make a Independent класс, в котором нам нужны поля отношения @OneToMany
ШАГ 1
public class AB {
private A a;
private B b; //@OneToMany with A in the Entity class definitions
public AB(){}
public AB(A a, B b){ ///Very Important to have this constructor
this.a=a;
this.b=b;
}
getter setter....
}
ШАГ 2
CriteriaQuery<AB> q = criteriaBuilder.createQuery(AB.class);
Root<A> fromA = criteriaQuery.from(A.class);
List<Predicate> predicates = new ArrayList<Predicate>();
Join<A,B> fromB = fromA.join("b", JoinType.INNER);/*"b",fieldName of B in entity Class A*/
criteriaQuery.select(criteriaBuilder.construct(AB.class,A,B));//looks AB's 2 param constr.
predicates.add(criteriaBuilder.equal(fromA.get("name"), filter.getName()));
predicates.add(criteriaBuilder.equal(fromB.get("salary"), filter.getSalary()));
..........
List<AB> ABDataList = typedQuery.getResultList();
for(AB eachABData :ABDataList){
....put in ur objects
obj.setXXX(eachABData.getA().getXXX());
obj.setYYY(eachABData.getB().getYYY());
}
Это даст все результаты, применяя все критерии к основной таблице A, и сравнивая первичный ключ таблицы B вместо внешнего ключа.