2012-04-15 33 views
5

Tôi muốn tạo truy vấn bằng cách sử dụng JPA CriteriaBuilder và tôi muốn thêm một mệnh đề ORDER BY. Đây là thực thể của tôi:Có thể đặt hàng bằng khóa tổng hợp với JPA và CriteriaBuilder

@Entity 
@Table(name = "brands") 
public class Brand implements Serializable { 

    public enum OwnModeType { 
     OWNER, LICENCED 
    } 

    @EmbeddedId 
    private IdBrand id; 
    private String code; 
    //bunch of other properties 
} 

Embedded lớp là:

@Embeddable 
public class IdBrand implements Serializable { 

    @ManyToOne 
    private Edition edition; 
    private String name; 
} 

Và cách tôi đang xây dựng truy vấn của tôi là như thế này:

CriteriaBuilder cb = em.getCriteriaBuilder(); 
CriteriaQuery<Brand> q = cb.createQuery(Brand.class).distinct(true); 
Root<Brand> root = q.from(Brand.class); 
if (f != null) { 
    f.addCriteria(cb, q, root); 
    f.addOrder(cb, q, root, sortCol, ascending); 
} 
return em.createQuery(q).getResultList(); 

Và đây là những chức năng được gọi là:

public void addCriteria(CriteriaBuilder cb, CriteriaQuery<?> q, Root<Brand> r) { 
} 

public void addOrder(CriteriaBuilder cb, CriteriaQuery<?> q, Root<Brand> r, String sortCol, boolean ascending) { 
    if (ascending) { 
     q.orderBy(cb.asc(r.get(sortCol))); 
    } else { 
     q.orderBy(cb.desc(r.get(sortCol))); 
    } 
} 

Nếu tôi cố gắng đặt sortCol một cái gì đó giống như "id.name" tôi nhận được lỗi sau:

javax.ejb.EJBException: java.lang.IllegalArgumentException: Unable to resolve attribute [id.name] against path

Bất kỳ ý tưởng làm thế nào tôi có thể thực hiện điều đó? Tôi đã cố gắng tìm kiếm trực tuyến, nhưng tôi không thể tìm thấy một gợi ý về vấn đề này ... Cũng sẽ rất tuyệt nếu tôi có thể làm tương tự ORDER BY khi tôi có một mối quan hệ @ManyToOne (ví dụ, "id.edition.number")

Trả lời

5

vấn đề là hiểu biết của bạn JPA sử dụng con đường. JPA Manual nói:

Path expression whose type is a persistable user class can be extended further by reusing the dot (.) operator. For example, c.capital.name is a nested path expression that continues from the Capital entity object to its name field. A path expression can be extended further only if its type is also a user defined persistable class. The dot (.) operator cannot be applied to collections, maps and values of simple types (number, boolean, string, date).

Trong trường hợp của bạn, bạn sử dụng id.edition.number, nơi IdBrand (id) không phải là người sử dụng persistable lớp.

Để giải pháp là con đường xây dựng biểu theo cách này: root.get("id").get("edition.number");


Để tránh vấn đề như vậy, bạn có thể viết một người thợ xây con đường, mà dựa trên javax.persistence.metamodel.Attribute.PersistentAttributeType sẽ quyết định cách con đường được xây dựng. Đối với các phần tử cơ bản - sử dụng .get(), cho các phần tử thu thập sử dụng .join().

Để bạn hiểu được lỗi của mình, bạn cần phải đọc thêm thông tin về đường dẫn JPA nói chung. Here is a good manual on JPA paths.

+0

Vâng đó là những gì nó nói trong câu trả lời khác mà tôi đã liên kết. Tôi thấy điều này thực sự gây phiền nhiễu và không hiểu tại sao nó không thể hoạt động tự động. Theo hiểu biết của bạn, tôi có gặp vấn đề tương tự nếu tôi sử dụng IdClass thay vì EmbeddedId không? – Kjir

+0

Vâng, nếu chúng ta nhìn vào [Phân cấp loại JPA] (http://www.objectdb.com/java/jpa/persistence/metamodel#Type_Interface_Hierarchy_), chúng ta có thể thấy, EntityType đó mở rộng IdentifiableType, vì vậy có lẽ @Id (@IdClass) là loại có thể nhận dạng, vì vậy bạn có thể làm điều đó. Bạn nên thử nó. Cũng nhận được PersistentType từ thuộc tính, sau đó bạn có thể xác định những gì bạn có thể làm với nó. – JMelnik

+0

Như tôi đang nói, ** có thể ** nó là có thể, vì vậy bạn nên kiểm tra PersistentType, và cung cấp nó ở đây nếu bạn có thể xin vui lòng. – JMelnik

1

Tôi thực sự tìm thấy câu trả lời về một vấn đề tương tự: JPA - Criteria API and EmbeddedId

Dưới đây là cách tôi cố định mã của tôi:

public void addOrder(CriteriaBuilder cb, CriteriaQuery<?> q, Root<Brand> r, String sortCol, boolean ascending) { 
    Path<?> p = r; 
    String []sortCols = sortCol.split("\\."); // This is a regexp, hence the escape backslash 
    for(String sc: sortCols) { 
     p = p.get(sc); 
    } 
    if (ascending) { 
     q.orderBy(cb.asc(p)); 
    } else { 
     q.orderBy(cb.desc(p)); 
    } 
} 
Các vấn đề liên quan