2012-07-09 39 views
5

Tương đối mới đối với JPA, vì vậy tôi có một loại câu hỏi kiến ​​trúc. Hãy nói rằng tôi có bảng EMPLOYEE và DEPARTMENT với nhiều đến một mối quan hệ (ví dụ: nhiều nhân viên làm việc cho một bộ phận):JPA - cột được tính làm thuộc tính hạng thực thể?

EMPLOYEE 
    EMPLOYEE_ID 
    EMPLOYEE_NAME 
    DEPARTMENT_ID 

DEPARTMENT 
    DEPARTMENT_ID 
    DEPARTMENT_NAME 

Vì vậy, tôi có thể xác định các đối tượng thích hợp cho người lao động và Bộ, không có vấn đề. Tuy nhiên, trong một cái nhìn Tôi muốn hiển thị danh sách các phòng ban với số lượng nhân viên làm việc cho bộ phận đó, một cái gì đó như thế này:

SELECT D.DEPARTMENT_NAME, 
     (SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID) NUMBER_OF_EMPLOYEES 
FROM DEPARTMENT D 

Tôi chỉ không chắc chắn chiến lược đúng đắn để thực hiện điều này sử dụng JPA là gì. .. Tôi không muốn luôn tìm nạp số lượng nhân viên cho thực thể của Sở vì chỉ có một chế độ xem khi cần.

Dường như Hibernate's @Formula sẽ là một trong những cách tiếp cận có thể, nhưng nó không phù hợp với tiêu chuẩn JPA.

Trả lời

4

Bạn có thể tạo bất kỳ đối tượng nào trong QL của mình bằng cú pháp "mới" - lớp của bạn chỉ cần một hàm tạo lấy các giá trị được trả về bởi truy vấn của bạn.

Ví dụ, với một lớp học như DepartmentEmployeeCount, với một constructor:

public DepartmentEmployeeCount(String departmentName, Integer employeeCount) 

bạn có thể sử dụng QL cái gì đó như:

SELECT NEW DepartmentEmployeeCount(D.DEPARTMENT_NAME, count(E.id)) from Department D left join D.employees E GROUP BY D.DEPARTMENT_NAME 

Hoặc nếu bạn chỉ cần chọn count (*) bạn có thể chỉ cần đưa kết quả truy vấn đến một Số.

Ngoài ra, để làm như vậy mà không có lớp DepartmentEmployeeCount, bạn có thể bỏ qua MỚI, vì vậy:

SELECT D.DEPARTMENT_NAME, count(E.id)  

này sẽ trả về một List<Object[]> nơi mỗi mục là một mảng của 2 yếu tố, departmentName và đếm .

Để trả lời câu hỏi sau này trong các nhận xét, để điền tất cả các trường của một Cục cộng với một trường nhân viên thoáng qua, một đề xuất sẽ là thực hiện 2 truy vấn. Điều này sẽ vẫn hiệu quả hơn truy vấn ban đầu của bạn (một lựa chọn cho mỗi số nhân viên).

Vì vậy, một truy vấn để đọc các phòng ban

SELECT D from Department D 

tạo cho bạn một List<Department>

Sau đó, một truy vấn thứ 2 trả về một mảng tạm thời:

SELECT D.DEPARTMENT_ID, count(E.id) from Department D left join D.employees E GROUP BY D.DEPARTMENT_ID 

tạo cho bạn một List<Object[]> với department_id và đếm trong đó.

Sau đó, bạn sử dụng danh sách thứ 2 để cập nhật thuộc tính đếm tạm thời trên danh sách đầu tiên của mình. (Bạn có thể thử chọn một Bản đồ để tìm kiếm dễ dàng hơn, nhưng tôi nghĩ đó là một tính năng Hibernate).

+0

Cảm ơn bạn @MattR cho câu trả lời của bạn. Giải pháp này có thể làm việc cho ví dụ đơn giản này. Nhưng nếu bảng (a) DEPARTMENT có nhiều cột khác ngoài NAME và tôi rõ ràng không muốn liệt kê tất cả chúng trong hàm tạo và (b) tôi vẫn muốn có nó như là thuộc tính của thực thể Bộ (với LAZY fetch loại) để có thể truy cập ở một nơi khác chỉ trong trường hợp. – AndreiM

+0

Câu hỏi hay, tôi chưa thử nó nhưng tôi nghĩ * bạn có thể sử dụng các lớp thực thể trong hàm tạo (vì vậy bạn sẽ không cần phải chọn tất cả các thuộc tính thực thể). Nếu tôi có cơ hội thử nó, tôi sẽ cập nhật câu trả lời của tôi ... tức là bạn có thể có một lớp DepartmentEmployees (nói) có một hàm tạo DepartmentEmployees (Department, Integer) và sử dụng SELECT mới DepartmentEmployees (D, count (E.id))) - không hoàn toàn những gì bạn đang yêu cầu nhưng gần hơn ... – MattR

+0

OK Tôi đã nghĩ về điều này trong bữa ăn trưa, do đó, cập nhật một số thông tin bổ sung. Nếu bạn thử bất kỳ đề xuất nào hoặc tìm giải pháp tốt hơn, vui lòng báo cáo lại – MattR

3

Tùy chọn 1: Tôi đã đề xuất điều này vì bạn không thích lộ trình khởi tạo mà MattR đã đề xuất.Bạn đã đề cập từ "xem" nhiều lần và tôi biết bạn đang nói về chế độ xem cho người dùng, nhưng tại sao không thiết lập chế độ xem trong cơ sở dữ liệu bao gồm các cột được tính và sau đó tạo thực thể chỉ đọc để ánh xạ tới cột?

Tùy chọn 2: Trả lời nhận xét của bạn về việc không muốn tạo chế độ xem. Bạn có thể tạo đối tượng chứa chứa đối tượng và cột được tính toán, sau đó giống như MattR gợi ý, bạn sử dụng một đối tượng mới trong lựa chọn của mình. Một cái gì đó như:

public class DepartmentInfo { 
    private Department department; 

    // this might have to be long or something 
    // just see what construct JPA tries to call 
    private int employeeCount; 

    public DepartmentInfo(Department d, int count) { 
     department = d; 
     employeeCount = count; 
    } 
    // getters and setters here 
} 

Sau đó, bạn chọn trở thành

SELECT new my.package.DepartmentInfo(D, 
     (SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID)) 
FROM DEPARTMENT D 

Với nó, bạn có thể sử dụng DepartmentInfo để có được các thuộc tính bạn quan tâm đến

+0

Điều đó có thể thực sự. Nhưng những gì tôi muốn chỉ là một tài sản bổ sung cho thực thể hiện tại của tôi, mà tôi có thể sử dụng trên một trang (và, có thể, ở một nơi khác). Có thực sự đáng để tạo ra một chế độ xem khác và một thực thể khác cho điều đó không? – AndreiM

+0

Điều bạn muốn _right now_ chỉ là một thuộc tính bổ sung cho thực thể hiện tại của bạn để sử dụng trên một trang và có thể là một thuộc tính khác. Và trong tương lai có thể thêm 3 nữa với 4 thuộc tính bổ sung và vân vân và vân vân. Trong mọi trường hợp, tôi đã thêm tùy chọn 2 vào câu trả lời của tôi. – digitaljoel

+0

Cảm ơn bạn, @digitaljoel, cho đến nay trông giống như cách tiếp cận tối ưu nhất trong kịch bản này. – AndreiM

1

Bạn có thể tạo ra một thành viên trong tổ chức của bạn như. một cột bổ sung và sau đó tham chiếu cột đó bằng bí danh trong truy vấn của bạn. Tên cột trong chú thích @Column phải khớp với bí danh.

Nói, đối với truy vấn ban đầu của bạn, bạn có thể thêm thành viên countEmployees như sau. Ngoài ra thêm insertable=falseupdatable=false nên người quản lý thực thể sẽ không cố gắng để bao gồm nó trong chèn hoặc cập nhật báo cáo:

public class Department { 

    @Column(name="DEPARTMENT_ID") 
    Long departmentId; 

    @Column(name="DEPARTMENT_NAME") 
    String departmentName; 

    @Column(name="countEmployees", insertable=false, updatable=false) 
    Long countEmployees; 

    //accessors omitted 

} 

Và truy vấn của bạn:

SELECT D.DEPARTMENT_NAME, 
(SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID) AS countEmployees 
FROM DEPARTMENT D 

này cũng áp dụng khi làm việc với mùa xuân dữ liệu JPA Repositories.

+0

Bạn có thể thực hiện tương tự bằng truy vấn JPA, không phải truy vấn gốc? – Arthur

+0

Chiến lược này không hoạt động. – Partha

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