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アノテーションを使用します。 これは、javax .persistence.NamedQueryをHibernate機能で拡張します。

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

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

すべての@NamedQueryアノテーションは、正確に1つのエンティティクラスまたはマップされたスーパークラスにアタッチされていることに注意することが重要です。 しかし、 名前付きクエリのスコープは永続性ユニット全体であるため、衝突を避けるためにクエリ名を慎重に選択する必要があります。 そして、エンティティ名をプレフィックスとして使用することでこれを実現しました。

エンティティに複数の名前付きクエリがある場合は、@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アノテーションを使用してさまざまなクエリ機能を設定できます。 例を見てみましょう:

@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<DeptEmployee> query = session.createNamedQuery("DeptEmployee_FindByEmployeeNumber", 
  DeptEmployee.class);
query.setParameter("employeeNo", "001");
DeptEmployee result = query.getSingleResult();

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

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プロパティを使用しました。

結果をマップする別の方法は、resultSetMappingプロパティを使用することです。 ここでは、事前定義されたSQLResultSetMappingの名前を指定できます。

resultClassresultSetMappingのいずれか1つしか使用できないことに注意してください。

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

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

Query<DeptEmployee> 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プロパティを使用していることに注意してください。 これは、Hibernateが純粋なネイティブスカラークエリをサポートしていないためです。 この問題を回避する方法は、resultClassまたはresultSetMapping。のいずれかを設定することです。

6. 結論

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

ソースコードは、GitHubから入手できます。