6

JPA は比較的新しいので、アーキテクチャに関する質問が 1 つあります。多対 1 の関係を持つ EMPLOYEE と DEPARTMENT テーブルがあるとします (つまり、多くの従業員が 1 つの部門で働いています)。

EMPLOYEE
  EMPLOYEE_ID
  EMPLOYEE_NAME
  DEPARTMENT_ID 

DEPARTMENT
  DEPARTMENT_ID
  DEPARTMENT_NAME

したがって、従業員と部門の適切なエンティティを定義できます。問題はありません。ただし、あるビューでは、次のように、その部門で働いている従業員数とともに部門のリストを表示したいと考えています。

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

JPAを使用してこれを達成するための正しい戦略が何であるかわかりません...必要なときにビューが1つしかないため、Departmentエンティティの従業員数を常に取得したくありません。

Hibernate の @Formula が 1 つの可能なアプローチのように見えますが、JPA 標準に準拠していません。

4

3 に答える 3

4

オプション 1: MattR が提案していたコンストラクター ルートが気に入らなかったため、これを提案しました。あなたは「ビュー」という言葉に何度か言及しましたが、ユーザーにビューについて話していたことは知っていますが、計算された列を含むデータベースにビューを設定してから、計算された列にマップする読み取り専用エンティティを作成してみませんか?列?

オプション 2: ビューを作成したくないというコメントへの回答として。エンティティと計算列を保持するコンテナ オブジェクトを作成し、MattR が示唆するように、select で new を使用できます。何かのようなもの:

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
}

次に、あなたの選択は

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

これにより、DepartmentInfo を使用して、関心のあるプロパティを取得できます。

于 2012-07-10T04:53:42.127 に答える
4

「新しい」構文を使用して、QL に任意のオブジェクトを作成できます。クラスには、クエリによって返された値を受け取るコンストラクターが必要なだけです。

たとえば、DepartmentEmployeeCount のようなクラスでコンストラクターを使用すると、次のようになります。

public DepartmentEmployeeCount(String departmentName, Integer employeeCount)

次のような QL を使用できます。

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

または、count(*) を選択しただけの場合は、クエリ結果を単純に数値にキャストできます。

または、DepartmentEmployeeCount クラスを使用せずに同じことを行うには、NEW を省略できます。

SELECT D.DEPARTMENT_NAME, count(E.id)    

List<Object[]>これは、各リスト項目が departmentName と count の 2 つの要素の配列であるを返します。

コメントでの後の質問に答えるには、Department のすべてのフィールドと一時的な employeeCount フィールドにデータを入力するには、2 つのクエリを実行することをお勧めします。これは、元のクエリ (各従業員数のサブセレクト) よりも効率的です。

部門を読み取るための 1 つのクエリ

SELECT D from Department D

あなたにList<Department>

次に、一時配列を返す 2 番目のクエリ:

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

List<Object[]>あなたにDEPARTMENT_IDとカウントを与えます。

次に、2 番目のリストを使用して、最初のリストの一時カウント プロパティを更新します。(このルックアップを簡単にするためにマップを選択することもできますが、それは Hibernate の機能だと思います)。

于 2012-07-09T23:25:24.290 に答える
1

エンティティにメンバーを追加の列として作成し、クエリでエイリアスを使用して参照することができます。@Column注釈の列名はエイリアスと一致する必要があります。

たとえば、元のクエリに対して、countEmployees次のようにメンバーを追加できます。また、追加insertable=falseupdatable=falseて、エンティティ マネージャーが挿入または更新ステートメントに含めようとしないようにします。

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

}

そしてあなたのクエリ:

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

これは、Spring Data Jpa リポジトリを操作する場合にも適用されます。

于 2016-07-05T00:17:11.457 に答える