Критерии JPA 2 с 3 таблици

Опитвам се да създам критерий за извличане на някои обекти от 3 таблици (Associate, Update и 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();
}

може ли някой да ми помогне Търсих, но не мога да намеря нито един пример с 3 обекта.


person Rafael Toledo    schedule 17.06.2013    source източник


Отговори (3)


Всяко съединение ви отвежда от левия тип параметър към десния. И така, 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)
);
person perissf    schedule 17.06.2013
comment
Работи като чар! Тези обединения по критерии ме подлудиха, но това помогна много! Благодаря perissf :) - person Rafael Toledo; 17.06.2013

За три участващи маси.

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;
}

}

person Smart Coder    schedule 18.10.2017
comment
Дали използването на множество условия като sql израз с WHERE x=y И a=b И c=d .... Или трябва да използвам метода and(Predicate), за да установя това? - person ; 10.04.2018
comment
това е като SQL израз с клауза Where. - person Smart Coder; 11.04.2018
comment
conditions.add(builder.equal(table3.get("Table1").get("memberId"), table1.get("memberId"))); Това означава, че класът Table3 има членска променлива Table1? Ами ако има връзка @OneToMany. И има List‹Table1›, как можем да направим това? - person Anil Bhaskar; 29.05.2019

Разгледайте този тест дори с повече от три таблици. Използвайте и статичен метамодел, вместо да използвате директни имена на атрибути.

    @Test
@Rollback(false)
@Transactional
public void   
fetch() {
    CriteriaBuilder cb = 
entityManager.getCriteriaBuilder();
    CriteriaQuery<Instructor> cq = 
cb.createQuery(Instructor.class);
    Root<Instructor> root = 
cq.from(Instructor.class);
    root.join(Instructor_.idProof);
    root.join(Instructor_.vehicles);
    Join<Instructor, Student> insStuJoin = 
root.join(Instructor_.students);
    insStuJoin.join(Student_.instructors);
    Join<Student, Vehicle> stuVehcileJoin.   
= insStuJoin.join(Student_.vehicles);
    Join<Vehicle, Document> 
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")
.value("2").value("3")));
}
person Vaneet Kataria    schedule 24.01.2019