Hibernate名前付きクエリ

Hibernate名前付きクエリ

1. 概要

HQLとSQLがデータアクセスオブジェクトに散在している主な欠点は、コードが読めなくなることです。 したがって、すべてのHQLとSQLを1か所にグループ化し、実際のデータアクセスコードでそれらの参照のみを使用することは理にかなっているかもしれません。 幸いなことに、Hibernateでは名前付きクエリを使用してこれを行うことができます。

名前付きクエリは、定義済みの変更不可能なクエリ文字列を持つ静的に定義されたクエリです。 これらはセッションファクトリの作成時に検証されるため、エラーが発生した場合にアプリケーションが迅速に失敗します。

この記事では、@NamedQueryおよび@NamedNativeQueryアノテーションを使用して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;

    // getters and setters
}

この例では、従業員番号に基づいて従業員を取得します。

3. 名前付きクエリ

これを名前付きクエリとして定義するには、org.hibernate.annotations.NamedQueryアノテーションを使用します。 Hibernate機能でjavax.persistence.NamedQueryを拡張します。

これをDeptEmployeeクラスのアノテーションとして定義します。

@org.hibernate.annotations.NamedQuery(name = "DeptEmployee_findByEmployeeNumber",
  query = "from DeptEmployee where employeeNumber = :employeeNo")

It’s important to note that every @NamedQuery annotation is attached to exactly one entity class or mapped superclass. But,since the scope of named queries is the entire persistence unit, we should select the query name carefully to avoid a collision.そして、エンティティ名をプレフィックスとして使用することでこれを実現しました。

エンティティに複数の名前付きクエリがある場合は、@NamedQueriesアノテーションを使用してこれらをグループ化します。

@org.hibernate.annotations.NamedQueries({
    @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindByEmployeeNumber",
      query = "from DeptEmployee where employeeNumber = :employeeNo"),
    @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindAllByDesgination",
      query = "from DeptEmployee where designation = :designation"),
    @org.hibernate.annotations.NamedQuery(name = "DeptEmployee_UpdateEmployeeDepartment",
      query = "Update DeptEmployee set department = :newDepartment where employeeNumber = :employeeNo"),
...
})

HQLクエリはDMLスタイルの操作にできることに注意してください。 したがって、selectステートメントのみである必要はありません。 たとえば、上記のDeptEmployee_UpdateEmployeeDesignationのように更新クエリを作成できます。

3.1. クエリ機能の構成

@NamedQuery annotationを使用してさまざまなクエリ機能を設定できます。 例を見てみましょう:

@org.hibernate.annotations.NamedQuery(
  name = "DeptEmployee_FindAllByDepartment",
  query = "from DeptEmployee where department = :department",
  timeout = 1,
  fetchSize = 10
)

ここでは、タイムアウト間隔とフェッチサイズを構成しました。 これら2つとは別に、次のような機能も設定できます。

  • cacheable –クエリ(結果)がキャッシュ可能かどうか

  • cacheMode –このクエリに使用されるキャッシュモード。これは、GET, IGNORE, NORMAL, PUT,またはREFRESHのいずれかになります。

  • cacheRegion –クエリ結果がキャッシュ可能である場合、使用するクエリキャッシュ領域に名前を付けます

  • comment –生成されたSQLクエリに追加されたコメント。 DBAを対象

  • flushMode –このクエリのフラッシュモード。ALWAYS, AUTO, COMMIT, MANUAL,またはPERSISTENCE_CONTEXTのいずれか

3.2. 名前付きクエリの使用

名前付きクエリを定義したので、それを使用して従業員を取得しましょう。

Query query = session.createNamedQuery("DeptEmployee_FindByEmployeeNumber",
  DeptEmployee.class);
query.setParameter("employeeNo", "001");
DeptEmployee result = query.getSingleResult();

ここでは、createNamedQueryメソッドを使用しました。 クエリの名前を受け取り、org.hibernate.query.Query objectを返します。

4. 名前付きネイティブクエリ

HQLクエリと同様に、ネイティブSQLを名前付きクエリとして定義することもできます。 これを行うには、@NamedNativeQueryアノテーションを使用できます。 @NamedQueryに似ていますが、もう少し構成が必要です。

例を使用して、このアノテーションを調べてみましょう。

@org.hibernate.annotations.NamedNativeQueries(
    @org.hibernate.annotations.NamedNativeQuery(name = "DeptEmployee_GetEmployeeByName",
      query = "select * from deptemployee emp where name=:name",
      resultClass = DeptEmployee.class)
)

これはネイティブクエリであるため、結果をマップするエンティティクラスをHibernateに指示する必要があります。 したがって、これを行うためにresultClass プロパティを使用しました。

結果をマッピングするもう1つの方法は、resultSetMapping propertyを使用することです。 ここでは、事前定義されたSQLResultSetMappingの名前を指定できます。

使用できるのはresultClassresultSetMappingのいずれかであることに注意してください。

4.1. 名前付きネイティブクエリの使用

名前付きネイティブクエリを使用するには、Session.createNamedQuery()を使用できます。

Query query = session.createNamedQuery("DeptEmployee_FindByEmployeeName", DeptEmployee.class);
query.setParameter("name", "John Wayne");
DeptEmployee result = query.getSingleResult();

または、Session.getNamedNativeQuery()

NativeQuery query = session.getNamedNativeQuery("DeptEmployee_FindByEmployeeName");
query.setParameter("name", "John Wayne");
DeptEmployee result = (DeptEmployee) query.getSingleResult();

これら2つのアプローチの唯一の違いは戻り値の型です。 2番目のアプローチは、QueryのサブクラスであるNativeQuery, を返します。

5. ストアドプロシージャと関数

@NamedNativeQueryアノテーションを使用して、ストアドプロシージャと関数の呼び出しを定義することもできます。

@org.hibernate.annotations.NamedNativeQuery(
  name = "DeptEmployee_UpdateEmployeeDesignation",
  query = "call UPDATE_EMPLOYEE_DESIGNATION(:employeeNumber, :newDesignation)",
  resultClass = DeptEmployee.class)

これは更新クエリですが、resultClass propertyを使用していることに注意してください。 これは、Hibernateが純粋なネイティブスカラークエリをサポートしていないためです。 そして、問題を回避する方法は、resultClass またはresultSetMapping.を設定することです。

6. 結論

この記事では、名前付きHQLおよびネイティブクエリを定義および使用する方法を説明しました。

ソースコードはover on GitHubで入手できます。