2015-05-17 17 views
7
  1. Nếu không sử dụng CriteriaQuery#select():Khi nào sử dụng mệnh đề lựa chọn trong API tiêu chuẩn JPA?

    public List<Address> getAddressOfManager(String designation, String name, String orderByColumn) { 
    
        Boolean ascending = false; 
        CriteriaBuilder cb = emanager.getCriteriaBuilder(); 
        CriteriaQuery<Address> cq = cb.createQuery(Address.class); 
        Root<Address> root = cq.from(Address.class); 
        //cq.select(root); <------------- 
        Join<Address, Employee> employeeAddress = root.join(Address_.employee); 
        Join<Employee,Project> employeeProject = employeeAddress.join(Employee_.project); 
        cq.where(cb.or(cb.equal(employeeProject.get(Project_.name), name),cb.equal(employeeAddress.get(Employee_.designation), designation))); 
        Order order = ascending ? cb.asc(root.get(orderByColumn)) 
          : cb.desc(root.get(orderByColumn)); 
        cq.orderBy(order); 
        List<Address> result = emanager.createQuery(cq).getResultList(); 
        return result; 
    } 
    
  2. Với CriteriaQuery#select():

    public List<Address> getAddressOfManager(String designation, String name, String orderByColumn) { 
    
        Boolean ascending = false; 
        CriteriaBuilder cb = emanager.getCriteriaBuilder(); 
        CriteriaQuery<Address> cq = cb.createQuery(Address.class); 
        Root<Address> root = cq.from(Address.class); 
        cq.select(root); //<---------------- 
        Join<Address, Employee> employeeAddress = root.join(Address_.employee); 
        Join<Employee,Project> employeeProject = employeeAddress.join(Employee_.project); 
        cq.where(cb.or(cb.equal(employeeProject.get(Project_.name), name),cb.equal(employeeAddress.get(Employee_.designation), designation))); 
        Order order = ascending ? cb.asc(root.get(orderByColumn)) 
          : cb.desc(root.get(orderByColumn)); 
        cq.orderBy(order); 
        List<Address> result = emanager.createQuery(cq).getResultList(); 
        return result; 
    } 
    

    Bây giờ, tôi bối rối như khi sử dụng select() trong JPA tiêu chí truy vấn.

+0

'cq.select (root); 'được suy ra trong tiêu chuẩn JPA sẽ chọn tất cả các lĩnh vực trong thực thể liên quan (ies) và do đó từ bảng cơ sở dữ liệu tương ứng (s). Tuy nhiên, bạn cần phải rõ ràng, khi bạn muốn chọn một vài trong số họ. – Tiny

Trả lời

9

Về cơ bản có hai cách để xác định hạn chiếu (hoặc đơn giản là nói thuật ngữ lựa chọn) trên giao diện CriteriaQuery<T> trong đó kết quả truy vấn là để được xác định:

CriteriaQuery<T> select(Selection<? extends T> selection); 
CriteriaQuery<T> multiselect(Selection<?>... selections); 

Thường thì thuật ngữ dự báo được sử dụng là lớp ứng cử viên (Address trong các ví dụ của bạn) của chính truy vấn đó. Nó có thể được ngầm định như trong ví dụ đầu tiên của bạn.

Truy vấn từ thực thể Address trong ví dụ đầu tiên của bạn không chỉ định rõ thuật ngữ dự báo của nó và nó giống như chọn chính xác lớp ứng cử viên trong trường hợp này.

Thực thể liên tục của ứng cử viên là thuật ngữ dự đoán duy nhất được suy diễn ngầm.


tuy nhiên khi kết quả dự kiến ​​của truy vấn là, một cái gì đó khác hơn là thực thể dai dẳng ứng cử viên thân, một số cấu trúc khác có sẵn để hình thành kết quả của truy vấn. Các cấu trúc này có sẵn trong giao diện CriteriaBuilder.

phương pháp để hình thành kết quả truy vấn:

CompoundSelection<Y> construct(Class<Y> result, Selection<?>... terms); 
CompoundSelection<Object[]> array(Selection<?>... terms); 
CompoundSelection<Tuple> tuple(Selection<?>... terms); 

Vì lợi ích của sự hoàn chỉnh mà thôi, tôi sẽ cố gắng để chứng minh mỗi trong số họ lần lượt với một ví dụ đơn giản cho mỗi người trong số họ.


Shaping kết quả truy vấn vào trường hợp của một lớp (một tổ chức phi dai dẳng) bởi construct():

Phương pháp construct() tạo ra một thể hiện của đối số lớp nhất định và gọi một constructor (của một tổ chức phi -nhân viên thực hiện) với các giá trị từ các điều khoản lựa chọn đầu vào. Các đối số này cho hàm tạo của một thực thể không liên tục (không phải là một thực thể, một lớp Java đơn giản) phải khớp với số, thứ tự và kiểu (kiểu dữ liệu) với các giá trị tương ứng với các điều kiện lựa chọn đầu vào, chẳng hạn.

CriteriaQuery<EmployeeDetails> q = cb.createQuery(EmployeeDetails.class); 
Root<Employee> root = q.from(Employee.class); 
q.select(cb.construct(EmployeeDetails.class, root.get(Employee_.empName), root.get(Employee_.salary)); 

EmployeeDetails trong trường hợp này, là một lớp Java đơn giản - một tổ chức phi dai dẳng mà có một nhà xây dựng mà phải mất hai tham số kiểu String (ví empName) và BigDecimal (ví salary).

Truy vấn trả về một List<EmployeeDetails> - một tổ chức phi dai dẳng từ chọn Employee s - một thực thể dai dẳng.

Tùy thuộc vào số hàng được trả về, truy vấn cũng có thể trả lại EmployeeDetails bằng cách sử dụng phương pháp getSingleResult().

Nhiều mục lựa chọn cũng có thể được kết hợp thành cụm từ lựa chọn kết hợp đại diện cho Object[] hoặc Tuple như được hiển thị bên dưới.

Shaping kết quả truy vấn vào một Object[]:

CriteriaQuery<Object[]> q = cb.createQuery(Object[].class); 
Root<Employee> root = q.from(Employee.class); 
q.select(cb.array(root.get(Employee_.empName), root.get(Employee_.salary)); 
List<Object[]> list = entityManager.createQuery(q).getResultList(); 

Như có thể thấy, các truy vấn trả về một List<Object[]>. Mỗi phần tử của danh sách này chứa một mảng dựa trên 0 là Object s - Object[].

Shaping kết quả truy vấn vào một Tuple:

CriteriaQuery<Tuple> q = cb.createTupleQuery(); 
Root<Employee> root = q.from(Employee.class); 
Selection<String> empName = root.get(Employee_.empName).alias("empName"); 
q.select(cb.tuple(empName, root.get(Employee_.salary).alias("salary"); 
List<Tuple> list = entityManager.createQuery(q).getResultList(); 

String employeeName = list.get(0).get("empName");//Referring to by using its alias (empName) 
String employeeSalary = list.get(0).get(1);//Referring to by using its index (salary) 

//Iterate over a list of tuples through a foreach loop using alias. 

for (Tuple tuple : list) { 
    System.out.println(tuple.get("empName") + " : " + tuple.get("salary")); 
} 

Truy vấn trả về một List<Tuple>. Các giá trị được giữ bởi một Tuple có thể truy cập được bằng chỉ số nguyên 0 dựa trên, sử dụng tên bí danh của TupleElement hoặc trực tiếp bởi TupleElement.

CriteriaBuilder#createTupleQuery() tương tự như CriteriaBuilder#createQuery(Tuple.class).

Sử dụng multiselect() để giải thích các điều khoản dựa trên loại kết quả:

Cụm từ nhập sẽ tự động được giải thích bởi multiselect() phương pháp dựa trên loại kết quả của CriteriaQuery để tự động đến hình dạng của kết quả - các kiểu trả về của số CriteriaQuery được đề cập. Ví dụ, ví dụ đầu tiên trong câu trả lời này có thể được viết lại bằng cách sử dụng multiselect() như sau.

CriteriaQuery<EmployeeDetails> q = cb.createQuery(EmployeeDetails.class); 
Root<Employee> root = q.from(Employee.class); 
q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary)); 

Kể từ khi loại kết quả là EmployeeDetails, phương pháp multiselect() giải thích về dự báo đối số của nó như các đối số nhà xây dựng của EmployeeDetails.

Lưu ý rằng một cấu trúc như thế này, cb.construct(EmployeeDetails.class, root.get(Employee_.empName), root.get(Employee_.salary) như được sử dụng trong ví dụ đầu tiên, không phải được sử dụng trong ví dụ trước sử dụng multiselect() tự động diễn giải thuật ngữ đối số dựa trên kiểu trả về của truy vấn và gọi hàm tạo trong lớp kết quả - EmployeeDetails.

Nếu truy vấn đã được xác định để trả lại một Tuple (hoặc một danh sách các Tuple s), phương pháp multiselect() với những lập luận chính xác cùng sẽ tạo ra Tuple trường hợp thay vì như hình dưới đây.

CriteriaQuery<Tuple> q = cb.createTupleQuery(); 
Root<Employee> root = q.from(Employee.class); 
q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary)); 

Không cần phải đề cập đến nhưng điều tương tự cũng có thể được viết lại để trả lại một Object[] (hoặc một danh sách các Object[] s).

CriteriaQuery<Object[]> q = cb.createQuery(Object[].class); 
Root<Employee> root = q.from(Employee.class); 
q.multiselect(root.get(Employee_.empName), root.get(Employee_.salary)); 

Trong cả hai trường hợp, phương pháp muliselect() tự động giải thích về dự báo đối số của nó dựa trên các kiểu trả về của truy vấn như đã nói trước đây là TupleObject[] tương ứng.

Nó cũng cần lưu ý rằng EcliseLink có bug mà vẫn còn được cố định trong khi lấy một thuật ngữ Boolean lựa chọn duy nhất trong cách này sử dụng multiselect() như trong this question.


Tùy thuộc vào nhà cung cấp JPA khác nhau, hành vi của các phương pháp multiselect() trở nên thú vị hơn với Object như một loại kết quả,

  • Nếu phương pháp multiselect() được sử dụng có thời hạn lựa chọn duy nhất, kiểu trả về là chính thuật ngữ được chọn. Tuy nhiên,
  • Nếu phương pháp multiselect() có chứa nhiều cụm từ nhập/cụm từ lựa chọn/thuật ngữ dự đoán, loại kết quả là Object[].

Tôi không chắc chắn về các nhà cung cấp khác nhau nhưng các điều khoản lựa chọn theo quy định của phương pháp multiselect() có thể không phải là mảng hoặc tập hợp (hoặc cụm từ có giá trị tuple). Các thuật ngữ phức hợp duy nhất có thể được cho phép dưới dạng đối số multiselect() là các đối số được tạo bởi phương thức construct() về cơ bản đại diện cho một phần tử duy nhất.


Ngoài các cấu trúc trên, việc sử dụng CriteriaQuery#select(Selection<? extends T> selection) là khá phổ biến khi sử dụng vô hướng/nhóm/tổng hợp/đơn có giá trị chức năng như count(), max(), min() vv và phụ truy vấn. Việc sử dụng các truy vấn phụ được loại trừ khỏi câu trả lời này cho ngắn gọn.

A Selection xác định những gì được chọn bởi truy vấn. Lựa chọn có thể là bất kỳ biểu thức đối tượng, biểu thức thuộc tính, hàm, lựa chọn phụ, hàm tạo hoặc hàm tổng hợp. Bạn có thể xác định bí danh cho một số Selection bằng cách sử dụng API bí danh().

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); 

// Count the total employees 
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(); 
Root employee = criteriaQuery.from(Employee.class); 
criteriaQuery.select(criteriaBuilder.count(employee)); //<------ 
Query query = entityManager.createQuery(criteriaQuery); 
Long result = query.getSingleResult(); 

// Maximum salary 
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(); 
Root employee = criteriaQuery.from(Employee.class); 
criteriaQuery.select(criteriaBuilder.max(employee.get("salary")); //<------ 
Query query = entityManager.createQuery(criteriaQuery); 
Long result = query.getSingleResult(); 

http://en.wikibooks.org/wiki/Java_Persistence/Criteria#Selection

+0

Cảm ơn Tiny, Nhưng tôi vẫn chưa rõ về nó. Bất kỳ URL nào để tham khảo đều có thể giúp ích rất nhiều. – Prem

+0

[Tham khảo JBoss] (https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/querycriteria.html), [Hướng dẫn Oracle - Java EE 7] (http://docs.oracle. com/javaee/7/tutorial/persistence-criteria.htm), [JPA WikiBook] (http://en.wikibooks.org/wiki/Java_Persistence/Criteria). – Tiny

+0

Bạn có tìm thấy một số khó khăn trong việc hiểu các đoạn mã hoặc thông tin văn bản dài không? Đó là một ví dụ đơn giản, đơn giản và bị cắt giảm được lặp đi lặp lại nhiều lần. Tôi đã trả lời dựa trên một blog mà tôi nhớ. Tôi dự định trích dẫn nhiều thứ từ blog đó nhưng rất tiếc, tôi không thể tìm thấy liên kết đó ngay bây giờ.Nhân tiện, câu hỏi cụ thể được trả lời bằng một câu lệnh duy nhất, "* Một thực thể bền vững ứng cử viên chính nó như là thuật ngữ chiếu duy nhất được suy diễn ngầm. *" – Tiny

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