[Java] JPA 2.1 Early Draft Explained - Java EE 7 making progress

Java Persistence API 2.1の初期ドラフトは、約1ヶ月前からご覧頂けるようになっています。JPA2は、Java EE7の一部として提出される最初のJSRの一つでした。 Java EE 7に含まれる他のいくつかの仕様(JavaServer Faces2.0、JAX- RS2.0、CDI1.1など)もまた、初期ドラフトが出てきますが、それらについては後日ブログでご紹介したいと思っています。

JSRs: Java Specification Requests - JSR 338: JavaTM Persistence 2.1
http://jcp.org/en/jsr/detail?id=338
JSR-000344 JavaServerTM Faces 2.2
http://jcp.org/aboutJava/communityprocess/edr/jsr344/
JSR-000339 JavaTM API for RESTful Web Services (JAX-RS) 2.0
http://jcp.org/aboutJava/communityprocess/edr/jsr339/index.html
JSR-000346 Contexts and Dependency Injection for JavaTM EE 1.1
http://jcp.org/aboutJava/communityprocess/edr/jsr346/index.html

JPA 2.1のキモとなる部分はこちら。
  • ストアドプロシージャのサポート
    事前定義済みのデータベース関数やユーザー定義のデータベース関数の呼び出しのサポートがJava Persistence query languageに追加されました。

    ストアドプロシージャを実行するためのStoredProcedureQueryを返すEntityManager.createXXXStoredProcedureQueryメソッドには様々な亜種があります。@NamedQueryのように、ストアドプロシージャ、引数、および結果のデータ型を指定し、命名する@NamedStoredProcedureQueryがあります。エンティティやマッピングされたスーパークラスにこのアノテーションを指定できます。アノテーションで指定された名前は、EntityManager.createNamedStoredProcedureQueryで使われます。IN、OUT、INOUTの引数を指定して、プロシージャからかえってくる値を取り出すことができます。以下はその例です。

    @Entity
    @NamedStoredProcedureQuery(name="topGiftsStoredProcedure", procedureName="Top10Gifts")
    public class Product {
     . . .
    }


    // クライアント側では…

    StoredProcedreQuery query = EntityManager.createNamedStoredProcedureQuery("topGiftsStoredProcedure");
    query.registerStoredProcedureParameter(1, String.class, ParameterMode.INOUT);
    query.setParameter(1, "top10");
    query.registerStoredProcedureParameter(2, Integer.class, ParameterMode.IN);
    query.setParameter(2, 100);
    // there are other setParameter methods for defining the temporal type of a parameter
    . . .
    query.execute();
    String response = query.getOutputParameterValue(1);


    初期ドラフトの3.8.6に詳細が記載されています。

  • Criteriaを用いたバルクの更新・削除
    CriteriaUpdate、CriteriaDeleteCommonAbstractQueryインターフェースが追加され、AbstractQueryインターフェースがリファクタリングされました。
    仕様の6.5.15からCriteriaUpdateのサンプルを引用します。

    CriteriaUpdate<Customer> q = cb.createCriteriaUpdate(Customer.class);
    Root<Customer> c = q.from(Customer.class);
    q.set(c.get(Customer_.status), "outstanding")
     .where(cb.lt(c.get(Customer_.balance), 10000));


    これはJPQLの以下のコードと同義です。

    UPDATE Customer c
    SET c.status = 'outstanding'
    WHERE c.balance < 10000


    このクエリは以下のように実行できます。

    @PersistenceContext EntityManager em;
    Query query = em.createQuery(q);
    query.executeUpdate();


    初期ドラフトの6.5.15からCriteriaDeleteのサンプルを引用します。

    CriteriaDelete<Customer> q = cb.createCriteriaDelete(Customer.class);
    Root<Customer> c = q.from(Customer.class);
    q.where(cb.equal(c.get(Customer_.status), "inactive"),
            cb.isEmpty(c.get(Customer_.orders)));


    これは以下のJPQLと同義です。

    DELETE FROM Customer c
    WHERE c.status = 'inactive'
    AND c.orders IS EMPTY


    このクエリは、前のサンプルと同様に、次のように実行できます。
    @PersistenceContext EntityManager em;
    Query query = em.createQuery(q);
    query.executeUpdate();


  • 新しい予約語
    Java Persistence query languageの予約語(FUNCTIONONTREAT)が追加されました。
    • FUNCTIONを用いた事前定義済み関数、およびユーザー定義関数
      JPQLではSELECT, WHERE or HAVING句で使うクエリの組み込み関数(CONCAT、SUBSTRING、TRIM、LENGTH、ABS、SQRTやCURRENT_DATE)を提供しています。. 仕様の4.6.17.3で、FUNCTION演算子を用いた事前定義済みデータベース関数やユーザー定義関数の呼び出し方を定義しています。演算子FUNCTIONを使って定義済みデータベース関数やユーザー定義関数を実行します。以下はサンプルです。

      SELECT c
      FROM Customer c
      WHERE FUNCTION(‘hasGoodCredit’, c.balance, c.creditLimit)


    • TREATを用いたダウンキャスト
      FROM句やWHERE句中のパス表現でダウンキャストをサポートするための TREATをサポートしています。演算子TREATを使うと、サブクラス固有の状態にアクセスすることができます。仕様の4.4.9に例があります。

      SELECT b.name, b.ISBN
      FROM Order o JOIN TREAT(o.product AS Book) b


      この例では、 OrderProductを結合していますが、nameISBNは、ProductクラスのサブクラスであるBookクラスの属性です。別の例を見てみましょう。

      SELECT e FROM Employee e
      WHERE TREAT(e AS Exempt).vacationDays > 10
      OR TREAT(e AS Contractor).hours > 100


      vacationDays Exemptクラスのemployeesのための属性であり、hoursContractorクラスの属性です。

    • ONを用いた結合条件
      SQLにおけるON句は表の関係を指定するために使用します。取り上げる行の条件を指定するWHERE句とは異なります。仕様の4.4.5.2のサンプルJPQLを見てみましょう。

      SELECT s.name, COUNT(p)
      FROM Suppliers s LEFT JOIN s.products p
      ON p.status = 'inStock'
      GROUP BY s.name


      SQLにマッピングすると、こうなります。

      SELECT s.name, COUNT(p.id)
      FROM Suppliers s LEFT JOIN Products p
      ON s.id = p.supplierId AND p.status = 'inStock'
      GROUP BY s.name


      LEFT JOINのためにs.id = p.supplierIdという条件を作成しています。 JPQLのON句があるために、追加のJOIN条件である p.status = 'inStock' もまた、先ほどの生成されたSQLに追加されています。このクエリの結果には、全てのサプライヤ(NULL値を含む)が含まれます。これは以下のクエリとは異なるものです。

      SELECT s.name, COUNT(p)
      FROM Suppliers s LEFT JOIN s.products p
      WHERE p.status = 'inStock'
      GROUP BY s.name


      このクエリの結果には在庫がないサプライヤは含まれません。
      ON句をサポートするFetchJoinCollectionJoinSetJoinListJoinMapJoinのインターフェースにもメソッドが追加されています。

  • CDIを用いるエンティティリスナー
    エンティティリスナーを使うと、非永続リスナクラスの横断的なライフサイクルイベントを処理できます。JPA 2.1では、エンティティリスナーはCDIを通してのdependency injection(依存性の注入)をサポートしています。通常のライフサイクルコールバックメソッドの @PrePersist@PostPersist@PreUpdate@PreRemove をエンティティ向けに利用できます。自身のライフサイクルのために@PostConstruct@PreDestroyを用いてエンティティリスナーをアノテートすることができます。 初期ドラフトの3.5.1に詳細が記載されています。

    jsr338-expertsのエイリアスやjpa-specのユーザーメーリングリストもご覧下さい。

    [jsr338-experts] injection into entity listeners (Expert Group Mailing List)
    http://java.net/projects/jpa-spec/lists/jsr338-experts/archive/2011-07/message/12
    [jpa-spec users] Integration with CDI (Users Mailing List)
    http://java.net/projects/jpa-spec/lists/users/archive/2011-07/message/1

  • 永続コンテキストの同期
    JPA 2では、永続コンテキストを基礎となるリソースマネージャと同期します。永続コンテキストになされた任意の更新は、リソースマネージャに伝えられます。JPA 2.1では、非同期永続コンテキストのコンセプトを導入しています。コンテナで管理されている非同期永続コンテキストを以下のように作成することができます。

    @PersistenceContext(synchronization=SynchronizationType.UNSYNCHRONIZED) EntityManager em;

    初期ドラフトの7.6.1に詳細があります。

  • テキストおよびjavadocsでいくつか説明があります。
初期ドラフトのAppendixに、このバージョンの仕様の包括的な変更リストが付いています。あちこちに変更箇所が明示されていて、JPA2以後の変更がわかるようになっています。

リファレンスの最終版はこちらです。
当然ながら、これらはGlassFish 4.0に取り入れられる予定です。


原文はこちら。
http://blogs.oracle.com/arungupta/entry/jpa_2_1_early_draft

0 件のコメント:

コメントを投稿