タグ:SqlResultSetMapping
美しさは見る人の目にあります。 そう”容易さ”はありません”:
SQL結果セットのマッピングの詳細と、ネイティブクエリ結果の処理を簡単に行います。http://t.co/WH4BTlClIP#JPA#Java#JavaEE
—Thorben Janssen(@thjanssen123)April15, 2015
ThorbenはJPAについて非常に優れた有用な記事を書いており、彼は最近、JPA2.1の新機能についての優れたシリーズを開始しました。 その中には、結果セットマッピングが含まれています。 CTMMCのようなwebサイトからの結果セットマッピングを知っているかもしれません。annotatiomania.comこのマッピング手順は次のように要約することができます。
a)マッピングを定義する
@SqlResultSetMapping( name = "BookAuthorMapping", entities = { @EntityResult( entityClass = Book.class, fields = { @FieldResult(name = "id", column = "id"), @FieldResult(name = "title", column = "title"), @FieldResult(name = "author", column = "author_id"), @FieldResult(name = "version", column = "version")}), @EntityResult( entityClass = Author.class, fields = { @FieldResult(name = "id", column = "authorId"), @FieldResult(name = "firstName", column = "firstName"), @FieldResult(name = "lastName", column = "lastName"), @FieldResult(name = "version", column = "authorVersion")})})
上記のマッピングはかなり簡単です。 データベース列をエンティティフィールドおよびエンティティ全体にマップする方法を指定します。 次に、このマッピングに名前("BookAuthorMapping"
)を付け、ネイティブJPAクエリなどでアプリケーション全体で再利用できます。
私は特にThorbenが次のように書いているという事実が好きです:
エンティティにこのような巨大な注釈ブロックを追加したくない場合は、XMLファイルでマッピングを定義することもできます
… そこで、巨大な注釈のブロックをXMLの巨大なブロックに置き換えることに戻ります。… 🙂
b)マッピングを適用する
マッピングが何らかのJavaタイプで静的に定義されたら、上記を適用してそれらのエンティティをフェッチできますBookAuthorMapping
List<Object> results = this.em.createNativeQuery( "SELECT b.id, b.title, b.author_id, b.version, " + " a.id as authorId, a.firstName, a.lastName, " + " a.version as authorVersion " + "FROM Book b " + "JOIN Author a ON b.author_id = a.id", "BookAuthorMapping").getResultList();results.stream().forEach((record) -> { Book book = (Book)record; Author author = (Author)record;});
まだBook
とAuthor
型を覚えておく必要があり、検証可能な型情報が実際には何にも添付されていないため、明示的にキャストする必要があることに注意してく
“複雑”の定義
さて、この記事はこれが”複雑な”マッピングであると主張しており、間違いなく、私は同意するでしょう。 単純な結合だけを持つこの非常に単純なクエリは、JPAを介してエンティティを実際にマップしたい場合は、すでにそのような注釈の混乱を引き起こし クエリがもう少し複雑になると、Thorbenのマッピング注釈を見たくありません。 そして、覚えておいてください、@SqlResultSetMapping
はマッピング(native! 私たちはsqlの土地にいて、一括フェッチ、非正規化、集約、およびその他の「派手な」SQLのものが王様です。問題はここにあります:
Java5が注釈を導入しました。 注釈はもともと”人工修飾子”として使用されることを意図していました。static
, final
, protected
(興味深いことに、Ceylonは注釈のみを知っており、修飾子はありません)。 これは理にかなっています。 Java言語設計者は、既存のコードを壊すことなく新しい修飾子/”キーワード”を導入することができます–”実際の”キーワードは予約語であり、言語で導入するのは難しい enum
を覚えていますか?
だから、注釈のための良いユースケース(そして少数しかありません)は次のとおりです:
@Override
-
@Deprecated
(しかし、コメント属性は空想されていただろう) @FunctionalInterface
JPA(および他のJava EE Api、およびSpring)は、注釈の使用について完全に奇抜になっています。 私の後に繰り返します:
言語
@Before
や@After
Javaがjava(@Before/@Afterのアイデアは、redditのlennoffのものでした)
上記を読むと、私の中には強い既視感があります。 あなたは次のことを覚えていますか?
Javaがチェック例外を悪用する前または後の言語はありません。
2020年までにJava注釈を深く後悔します。
アノテーションはJava型システムでは大きな疣贅です。 彼らは非常に限られた正当化された使用を持っており、私たちのJavaエンタープライズ開発者が最近やっていることは、絶対に”正当化”の範囲内ではあ 私たちは、実際にコードを書くべきものの設定のためにそれらを乱用しています。
jOOQ(またはsqlのジェネリックと型安全性を活用する他のAPI)で同じクエリを実行する方法は次のとおりです):
Book b = BOOK.as("b");Author a = AUTHOR.as("a");DSL.using(configuration) .select(b.ID, b.TITLE, b.AUTHOR_ID, b.VERSION, a.ID, a.FIRST_NAME, a.LAST_NAME, a.VERSION) .from(b) .join(a).on(b.AUTHOR_ID.eq(a.ID)) .fetch() .forEach(record -> { BookRecord book = record.into(b); AuthorRecord author = record.into(a); });
この例では、JPA2.1の注釈とクエリの両方を組み合わせています。 投影された”エンティティ”に関するすべてのメタ情報は、すでにクエリに含まれているため、Result
メソッドによって生成されたfetch()
に含まれています。 しかし、それは本当に問題ではありません、ここでのポイントは、このラムダ式…
record -> { BookRecord book = record.into(b); AuthorRecord author = record.into(a);}
… それはあなたが望むものにすることができます! 以前のブログ記事で示したより洗練された例のように:
- Ormの必要はもうありません
- jOOQとJavaFXを使用してSQLデータをチャートに変換
マッピングは、関数を使用してその場でアドホックに定義できます。 関数は、入力を受け取り、出力を生成し、完全にステートレスであるため、理想的なマッパーです。 そして、Java8の関数についての最も良いことは、それらがJavaコンパイラによってコンパイルされ、マッピングの型チェックに使用できることです。 また、オブジェクトに関数を割り当てることができ、与えられたマッピングアルゴリズムを数回使用できる場合に関数を再利用できます。実際、SQLSELECT
句自体はそのような関数です。 入力タプル/行を出力タプル/行に変換する関数で、追加の式を使用してその関数をその場で適応させることができます。
前のJPA2.1ネイティブSQLステートメントと@SqlResultSetMapping
の例では、何かを入力チェックする方法は絶対にありません。 列名の変更を想像してみてください:
List<Object> results = this.em.createNativeQuery( "SELECT b.id, b.title as book_title, " + " b.author_id, b.version, " + " a.id as authorId, a.firstName, a.lastName, " + " a.version as authorVersion " + "FROM Book b " + "JOIN Author a ON b.author_id = a.id", "BookAuthorMapping").getResultList();
あなたは違いに気づきましたか? b.title
列の名前がbook_title
に変更されました。 SQL文字列で。 これは、実行時に爆発します! あなたも適応しなければならないことを覚えておく方法
@FieldResult(name = "title", column = "title")
… 逆に、@FieldResult
のcolumn
の名前を変更すると、この"BookAuthorMapping"
が使用されている場所を確認し、それらのクエリの列名も変更する必要があることを覚えておく方法。
@SqlResultSetMapping( name = "BookAuthorMapping", ...)
あなたは上記のいくつかに同意するかもしれませんし、同意しないかもしれません。 JPAの代替としてjOOQが好きかもしれませんし、好きではないかもしれませんが、それは完全に問題ありません。 しかし、それは事実に同意することは本当に難しいです:
- Java5は非常に便利な注釈を導入しました
- Java EE/SpringはXMLを置き換えるためにこれらの注釈を大きく悪用しました
- Javaに並列ユニバース型システムが7715>
- java se9-10は、より多くの素晴らしい言語機能を導入します
- 構成(xmlまたは注釈)が最初にコードであるべきであることが明らかになりました
- JPA2.1は新しいEJB2.0になりました:私が言ったように廃止された
。 反対するのは難しい。 または他の言葉で:
コードは構成よりもアルゴリズムを表現する方がはるかに優れています
私は個人的に会議で何度もThorbenに会ったことがあります。 ここでのこの暴言は個人的に意味されていませんでした、Thorben:-)JPAについてのあなたの記事は非常に興味深いです。 この記事の読者がJPAを使用している場合は、Thorbenのブログをチェックしてください:http://www.thoughts-on-java.org。
その間に、私は尊敬されるタイトル”The Annotatiomaniac of The Year2015″にThorbenを指名したいと思います
Write a Reply or Comment