2010-06-14 15 views
7

Tôi thích loại an toàn CriteriaQuery mang lại cho JPA 2.0 nhưng nó cũng mang lại một chút mã tấm nồi hơi. Ví dụ, giả sử tôi có một thực thể tên là NamedEntity, đơn giản chỉ có một id và một trường String được gọi là "name" (giả sử nó có ràng buộc duy nhất được đặt thành true). Dưới đây là những gì các NamedEntityManager có thể trông giống như:Có cách nào để giảm số lượng mã tấm nồi hơi liên kết với một CriteriaQuery (trong JPA 2.0) không?

public class NamedEntityManager 
{ 
    //inject using your framework 
    EntityManager entityManager; 

    //retrieve all existing entities of type NamedEntity from DB 
    public Iterable<NamedEntity> queryAll() 
    { 
     CriteriaBuilder builder = entityManager.getCriteriaBuilder(); 
     CriteriaQuery<NamedEntity> query = builder.createQuery(NamedEntity.class); 
     return entityManager.createQuery(query).getResultList(); 
    } 

    //retrieve a single entity of type NamedEntity from DB using specified name 
    public NamedEntity queryByName(String name) 
    { 
     CriteriaBuilder builder = entityManager.getCriteriaBuilder(); 
     CriteriaQuery<NamedEntity> query = builder.createQuery(NamedEntity.class); 
     Root<NamedEntity> root = query.from(NamedEntity.class); 
     query = query.where(root.<NamedEntity>get("name").in(name)); 

     //skipped the try/catch block for the sake of brevity 
     return entityManager.createQuery(query).getSingleResult(); 
    } 
} 

Có cách nào để ngưng tụ mã để tránh sao chép/dán các dòng cùng một mã vào mỗi phương pháp truy vấn? Có lẽ bằng cách nào đó tái sử dụng đối tượng CriteriaQuery?

+0

Tình huống này có thể dễ dàng được giải quyết bằng chiến lược. Chỉ cần tạo một phương thức riêng, phương thức này sẽ lấy một tham số (một giao diện) kiểu, WhereClauseBuilder, phương thức riêng sẽ nhận được phần khác nhau của nó (mệnh đề where) từ tham số này thông qua một lời gọi phương thức truyền các tiêu chí và truy vấn tới nó. Tất cả các phương thức công khai, sẽ chỉ gọi phương thức riêng với một đối tượng cụ thể WhereClauseBuilder trả về vị từ cần thiết trong đó mệnh đề. –

Trả lời

0

Có vẻ như không có cách nào để giảm số lượng mã. Tôi đoán một cái gì đó đã được hy sinh để đạt được an toàn loại.

4

Tôi đang tìm kiếm một cái gì đó như thế, bạn có thể xem Querydsl (LGPL được cấp phép) có thể có JPA làm phụ trợ.

Im vẫn đọc nó, nhưng từ ví dụ của họ, có vẻ khá sạch sẽ.

HQLQuery q = new HibernateQuery(session); 
QCat cat = new QCat("cat"); // query type 
List<Cat> cats = q.from(cat).where(cat.name.between("A", "B")).list(cat); 
+0

Mặc dù khung này không liên quan đến API tiêu chí và tự đứng vững, nó chắc chắn đáng xem xét. Cảm ơn bạn đã đề cập đến điều này, tôi sẽ khám phá nó khi tôi có cơ hội! – Andrey

+0

Chỉ cần chỉnh sửa nhỏ, Querydsl được cấp phép LGPL, chứ không phải giấy phép GPL. –

4

Trong JPA 2.1, rất có thể có thể trộn JPQL và tiêu chí. Với cách tiếp cận như vậy bạn có thể xác định truy vấn cơ sở với JPQL và sau đó sử dụng API tiêu chí để tự động thêm các phần nhỏ.

Tôi tìm thấy API sẽ ít tiết hơn, vì bạn chỉ cần sử dụng các phần nhỏ của nó.

+1

Tôi không chắc chắn nếu nó sẽ làm cho tinh thần để trộn JPQL với tiêu chí truy vấn. Bao gồm cả JPQL sẽ đi ngược lại ý tưởng chính đằng sau API tiêu chí - để cung cấp sự an toàn kiểu thời gian biên dịch. – Andrey

+2

Đó là một sự cân bằng tất nhiên. Nó cũng giống như sử dụng EL và trong một số trường hợp chú thích. Bạn đang giao dịch trong thời gian biên dịch an toàn cho tính linh hoạt và ít mã tiết hơn. Dù sao, rất nhiều người nghĩ rằng nó làm cho cảm giác như Linda (spec chì) đang nghiêm túc xem xét điều này cho JPA 2.1. Lựa chọn sau đó là của bạn: JPQL tinh khiết, JPQL được trộn với Tiêu chí và ngay cả trong Criterias bạn có các biến thể an toàn và không an toàn loại. Sử dụng những gì làm việc cho bạn. –

0

Way lỗi thời, bài này, nhưng tôi muốn thêm những gì tôi vừa mới được xây dựng cho các truy vấn đơn giản

public static class Jpa2Whatsoever { 

    private final EntityManager em; 

    public class Jpa2WhatsoeverProgress<T> { 

     private CriteriaQuery<T> cq; 
     private List<Predicate> predicates = new ArrayList<>(); 
     private Root<T> root; 

     public Jpa2WhatsoeverProgress(Class<T> type) { 
      this.cq = em.getCriteriaBuilder().createQuery(type); 
      this.root = cq.from(type); 

     } 

     public Jpa2WhatsoeverProgress<T> where(String attributeName, Object value) { 

      Predicate equal = em.getCriteriaBuilder().equal(root.get(attributeName), value); 

      predicates.add(equal); 
      return this; 
     } 

     public List<T> getResultList() { 
      Predicate[] predicatesArray = new Predicate[predicates.size()]; 
      TypedQuery<T> typedQuery = em.createQuery(cq.select(root).where(predicates.toArray(predicatesArray))); 

      List<T> resultList = typedQuery.getResultList(); 

      return Collections.unmodifiableList(resultList); 
     } 

    } 

    public Jpa2Whatsoever(EntityManager entityManager) { 
     this.em = entityManager; 
    } 

    public <T> Jpa2WhatsoeverProgress<T> select(Class<T> type) { 
     return new Jpa2WhatsoeverProgress<T>(type); 
    } 
} 

Bạn có thể sử dụng nó như thế này

List<MyEntity> matchingEntities = new Jpa2Whatsoever(entityManager).select(MyEntity.class).where("id", id).where("due", new Date()).getResultList(); 

Cuối cùng tôi dừng lại này. Chủ yếu là vì tôi thấy rằng tôi đã chỉ có hai câu hỏi và tôi sẽ phải mở rộng DSL để có được những đặc điểm truy vấn cần thiết vào nó, chẳng hạn như

  • lớn hơn, nhỏ hơn
  • hỗ trợ
  • metamodel
  • QueryBuilder.currentDate() và như nhau.

Hơn nữa, tôi thấy nó xấu xí khi luôn gọi where trong khi thực tế nó tương ứng với một số and SQLly hơn. Dù sao, nếu ai đó quan tâm đến một API truy vấn rất đơn giản, nó vẫn đáng để thử.

BTW: Quên tên, đây là nguyên mẫu, không có gì khác.

Các vấn đề liên quan