Hibernateクエリからカスタムクラスへのマッピング

1概要

Hibernateを使用してデータベースからデータを取得するとき、デフォルトでは、取得したデータを使用して、要求されたオブジェクトのオブジェクトグラフ全体を構築します。しかし、時にはデータの一部だけを取り出したいことがあります。できればフラット構造にします。

このクイックチュートリアルでは、カスタムクラスを使用してHibernateでこれを実現する方法を説明します。

2エンティティ

まず、データを取得するために使用するエンティティを見てみましょう。

@Entity
public class DeptEmployee {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long id;

    private String employeeNumber;

    private String designation;

    private String name;

    @ManyToOne
    private Department department;

   //constructor, getters and setters
}

@Entity
public class Department {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long id;

    private String name;

    @OneToMany(mappedBy="department")
    private List<DeptEmployee> employees;

    public Department(String name) {
        this.name = name;
    }

   //getters and setters
}

ここでは、 DeptEmployee Department の2つのエンティティがあります。簡単にするために、 DeptEmployee は1つの__Departmentにのみ属することができるとしましょう。

しかし、 Department には複数の DeptEmployees を含めることができます。

3カスタムクエリ結果クラス

すべての従業員のリストを、名前と部署名だけで印刷したいとしましょう。

通常、このようなクエリでこのデータを取得します。

Query<DeptEmployee> query = session.createQuery("from com.baeldung.hibernate.entities.DeptEmployee");
List<DeptEmployee> deptEmployees = query.list();

これにより、全従業員、全従業員の資産、関連部門、およびその全資産が取得されます。

しかし、この特定のケースでは、** 従業員の名前と部門の名前だけが必要なので、これは少しコストがかかります。

必要な情報だけを取得する方法の1つは、select句でプロパティを指定することです。

しかし、これを行うと、Hibernateは__Objectsのリストではなく配列のリストを返します。

Query query = session.createQuery("select m.name, m.department.name from com.baeldung.hibernate.entities.DeptEmployee m");
List managers = query.list();
Object[]manager = (Object[]) managers.get(0);
assertEquals("John Smith", manager[0]);
assertEquals("Sales", manager[1]);

ご覧のとおり、返されたデータは処理が少し面倒です。しかし、幸いなことに、Hibernateにこのデータをクラスに追加させることができます。

取得したデータを次のものに移入するために使用する Result クラスを見てみましょう。

public class Result {
    private String employeeName;

    private String departmentName;

    public Result(String employeeName, String departmentName) {
        this.employeeName = employeeName;
        this.departmentName = departmentName;
    }

    public Result() {
    }

   //getters and setters
}

このクラスは実体ではなく、単なるPOJOであることに注意してください。ただし、パラメータとして設定したいすべての属性を受け取るコンストラクタを持つ限り、エンティティを使用することもできます。

次のセクションでコンストラクタが重要である理由がわかります。

4 HQL でコンストラクタを使用する

それでは、このクラスを使用するHQLを見てみましょう。

Query<Result> query = session.createQuery("select new com.baeldung.hibernate.pojo.Result(m.name, m.department.name)"
  + " from com.baeldung.hibernate.entities.DeptEmployee m");
List<Result> results = query.list();
Result result = results.get(0);
assertEquals("John Smith", result.getEmployeeName());
assertEquals("Sales", result.getDepartmentName());

ここでは、取得したいプロパティと一緒に __Result classで定義したコンストラクタを使用します。これは、列から取り込まれたデータを含む Result__オブジェクトのリストを返します。

ご覧のとおり、返されたリストはオブジェクト配列のリストを使用するよりも処理が簡単です。

クエリでクラスの完全修飾名を使用する必要があることに注意することが重要です。

5 ResultTransformerを使う

HQLクエリでコンストラクタを使用する代わりに、__ResultTransformerを使用することもできます。

Query query = session.createQuery("select m.name as employeeName, m.department.name as departmentName"
  + " from com.baeldung.hibernate.entities.DeptEmployee m");
query.setResultTransformer(Transformers.aliasToBean(Result.class));
List<Result> results = query.list();
Result result = results.get(0);
assertEquals("John Smith", result.getEmployeeName());
assertEquals("Sales", result.getDepartmentName());

取得したデータを使用して __Result オブジェクトを生成するには、 Transformers.aliasToBean() __メソッドを使用します。

したがって、select文の列名またはその別名が __Result __classのプロパティと一致するようにする必要があります。

6. 結論

この記事では、カスタムクラスを使用して読みやすい形式でデータを取得する方法を説明しました。

この記事に付随するソースコードはhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/hibernate5[GitHubで利用可能]です。