Критерии JPA 2 с 3 таблицами
Я пытаюсь создать критерий для извлечения некоторых объектов из трех таблиц (Associate, Update and Detail). В "Подробности" содержится ссылка на "Связать" и "Обновить", а в "Обновлении" содержится ссылка на список деталей. Моя цель состоит в том, чтобы получить список обновлений, у которого есть по крайней мере деталь с нулевым значением в указанном поле, с учетом ассоциированного идентификатора. В JPQL было легко сделать, но клиент сказал, что это должно быть закодировано с критериями.
Мой JPQL был:
public List<Update> getUpdates(long associateId) {
TypedQuery<Update> query = em.createQuery("select distinct u from Update u, Detail dt, Associate a "
+ "where dt.update = u and dt.associate = a and a.associateId = :id and "
+ "dt.ack_date is null", Update.class);
query.setParameter("id", associateId);
return query.getResultList();
}
Я попробовал следующее, но он просто вернул все обновления в базе данных:
public List<Update> getUpdates(long associateId) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Update> query = builder.createQuery(Update.class);
Root<Update> fromUpdates = query.from(Update.class);
Root<Associate> fromAssociate = query.from(Associate.class);
Root<Detail> fromDetail = query.from(Detail.class);
Join<Detail, Associate> associateJoin = fromDetail.join("associate");
Join<Detail, Update> updateJoin = fromDetail.join("update");
TypedQuery<Update> typedQuery = em.createQuery(query
.select(fromUpdates)
.where(builder.and(
builder.equal(fromAssociate.get("associateId"), associateId),
builder.equal(fromDetail.get("associate"), associateJoin),
builder.equal(fromDetail.get("update"), updateJoin),
builder.isNull(fromDetail.get("ack_date"))
))
.orderBy(builder.asc(fromUpdates.get("updateId")))
.distinct(true)
);
return typedQuery.getResultList();
}
Может ли кто-нибудь мне помочь? Я искал, но не могу найти пример с тремя объектами.
Ответы
Ответ 1
Каждое соединение возвращает вас от параметра leftish type к правильному. Итак, объединение details
моего кода (вторая строка) начинается с fromUpdates
, то есть Path<Update>
, и создает что-то, что за кулисами, также Path<Detail>
. Из этого вы можете создавать другие объединения. Попробуйте (код не проверен):
Root<Update> fromUpdates = query.from(Update.class);
Join<Update, Detail> details = fromUpdates.join("details");
Join<Detail, Associate> associate = details.join("associate");
List<Predicate> conditions = new ArrayList();
conditions.add(builder.equal(associate.get("associateId"), associateId));
conditions.add(builder.isNull(details.get("ack_date")));
TypedQuery<Update> typedQuery = em.createQuery(query
.select(fromUpdates)
.where(conditions.toArray(new Predicate[] {}))
.orderBy(builder.asc(fromUpdates.get("updateId")))
.distinct(true)
);
Ответ 2
Для трех задействованных таблиц.
CriteriaBuilder builder = theEntityManager.getCriteriaBuilder();
CriteriaQuery query1 = builder.createQuery(BasicMemberInfo.class);
Root<Table1> table1 = query1.from(Table1.class);
Root<Table2> table2 = query1.from(Table2.class);
Root<Table3> table3 = query1.from(Table3.class);
List<Predicate> conditions = new ArrayList();
conditions.add(builder.equal(table3.get("Table1").get("memberId"), table1.get("memberId")));
conditions.add(builder.equal(table2.get("tableid").get("memberId"), table1.get("memberId")));
conditions.add(builder.equal(table2.get("indicator"), 'Y'));
conditions.add(builder.equal(table3.get("StatusCd"), "YES"));
TypedQuery<BasicCustInfo> typedQuery = theEntityManager.createQuery(
query1.multiselect(table1.get("memberId"), table2.get("AcctId"))
.where(conditions.toArray(new Predicate[] {}))
);
List<BasicMemberInfo> custList = typedQuery.getResultList();
открытый класс BasicMemberInfo {
String memberId;
String AcctId;
public BasicCustInfo() {
// TODO Auto-generated constructor stub
}
public BasicMemberInfo( BigDecimal memberId,String AcctId ) {
this.memberId = memberId;
this.AcctId = AcctId;
}
public BigDecimal getmemberId() {
return memberId;
}
public void setmemberId(BigDecimal memberId) {
memberId = memberId;
}
public String getAcctId() {
return AcctId;
}
public void setAcctId(String AcctId) {
AcctId = AcctId;
}
}
Ответ 3
Оформить этот тест с более чем тремя таблицами. Также используйте статическую метамодель вместо использования прямых имен атрибутов.
@Test @Rollback (false) @Transactional public void fetchFullDataWithJPQLQueryWithEqualEntityGr aph() {CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Instructor.class); CriteriaQuery cq = cb.createQuery(Instructor.class); Root root = cq.from(Instructor.class); Root root = cq.from(Instructor.class); root.join(Instructor_.idProof); root.join(Instructor_.idProof); root.join(Instructor_.vehicles); root.join(Instructor_.vehicles); Join insStuJoin = root.join(Instructor_.students); Присоединяйтесь insStuJoin = root.join(Instructor_.students); insStuJoin.join(Student_.instructors); insStuJoin.join(Student_.instructors); Join stuVehcileJoin. Присоединяйтесь к stuVehcileJoin.
= insStuJoin.join(Student_.vehicles);= insStuJoin.join(Student_.vehicles); Join vehicleDocumentJoin = stuVehcileJoin.join(Vehicle_.documents); Присоединитесь к vehicleDocumentJoin = stuVehcileJoin.join(Vehicle_.documents);
DataPrinters.
listDataPrinter.accept.
(queryExecutor.fetchListForCriteriaQuery
(cq.select(root).where
(cb.greaterThan(root.get(Instructor_.id), 2),
cb.in(vehicleDocumentJoin.get
(Document_.name)).value("1")
DataPrinters.
listDataPrinter.accept.
(queryExecutor.fetchListForCriteriaQuery
(cq.select(root).where
(cb.greaterThan(root.get(Instructor_.id), 2),
cb.in(vehicleDocumentJoin.get
(Document_.name)).value("1")
.value("2").value("3")));.value( "2") значение ( "3"))). } }