17

私の質問はこれです: ステートレス Web アプリケーションで JPA の役割はありますか?merge

mergeJPAでの操作については、SOに関する多くの議論があります。より手動の Do-It-Yourself プロセス (エンティティ マネージャーを介してエンティティを見つけて変更を加える) による JPA マージとは対照的な、この件に関する優れた記事もあります。

@Version私のアプリケーションには、楽観的ロックを利用するために注釈を使用するリッチ ドメイン モデル (ala ドメイン駆動設計) があります。また、RESTful Web サービスの一部としてネットワーク経由で送信する DTO も作成しました。この DTO 層の作成により、クライアントに必要なものすべてを送信し、不要なものを送信することもできます。

これまでのところ、これがかなり典型的なアーキテクチャであることは理解しています。私の質問は、既存のオブジェクトを更新 (つまり、HTTP PUT) する必要があるサービス メソッドについてです。この場合、1) JPA Merge と 2) DIY の 2 つのアプローチがあります。

私が理解していないのは、JPAマージが更新を処理するためのオプションと見なされることさえあるということです。これが私の考えであり、私が理解できないことがあるかどうか疑問に思っています:

1) ワイヤ DTO から切り離された JPA エンティティを適切に作成するには、バージョン番号を正しく設定する必要があります。そうしないと、OptimisticLockException がスローされます。しかし、JPAの仕様には次のように書かれています:

エンティティは、バージョン フィールドまたはプロパティの状態にアクセスしたり、アプリケーションがバージョンにアクセスするために使用するメソッドをエクスポートしたりできますが、バージョン値を変更してはなりません[30]。オブジェクトの version 属性の値を設定または更新できるのは、持続性プロバイダーだけです。

2) Merge は双方向のリレーションシップを処理しません...後ろ向きのフィールドは常に null になります。

3) フィールドまたはデータが (部分的な更新のために) DTO から欠落している場合、JPA マージはそれらの関係を削除するか、それらのフィールドを無効にします。Hibernate は部分的な更新を処理できますが、JPA マージは処理できません。DIY は部分的な更新を処理できます。

4) マージ メソッドが最初に行うことは、データベースにエンティティ ID をクエリすることです。そのため、DIY よりもパフォーマンス上の利点はありません。

5) DYI 更新では、エンティティをロードし、DTO に従って変更を行います。JPAコンテキストは作業単位パターンをすぐに実装するため、 merge呼び出しも呼び出しもありません。persist

私はこれをまっすぐに持っていますか?

編集:

6) 遅延ロードされたリレーションシップに関するマージの動作は、プロバイダー間で異なる場合があります

4

2 に答える 2

14

Merge を使用するには、エンティティの完全な表現を送受信するか、サーバー側の状態を維持する必要があります。些細な CRUD-y タイプの操作の場合、簡単で便利です。私は、クライアントにエンティティ全体を見せても意味のあるセキュリティ上の危険がないステートレス Web アプリで、これを何度も使用してきました。

ただし、すぐに関連する情報のみを渡すように既に操作を減らしている場合は、対応するサービスも手動で記述する必要があります。

「DIY」更新を行うときは、DTO でバージョン番号を渡し、データベースから出てくるものと手動で比較する必要があることを覚えておいてください。そうしないと、マージでより単純なアプローチを使用していた場合に発生する「ユーザーの思考時間」にまたがる楽観的ロックが得られません。

  1. プロバイダーによって作成されたエンティティのバージョンを変更することはできませんが、newキーワードを使用してエンティティ クラスの独自のインスタンスを作成した場合は問題なく、それにバージョンを設定することが期待されます。

  2. 永続的な表現を提供するインメモリ表現と一致させます。これには、null にすることも含まれます。オブジェクトがマージされると、そのオブジェクトは破棄され、マージによって返されたものに置き換えられることになっていることに注意してください。オブジェクトをマージしてから、それを使い続けることは想定されていません。その状態は仕様によって定義されていません。

  3. 真実。

  4. ほとんどの場合、DIY ソリューションもエンティティ ID を使用しており、任意のクエリを使用していない場合に限ります。(クエリよりも 'find' メソッドを使用する利点は他にもあります。)

  5. 真実。

于 2013-01-03T15:16:52.900 に答える
4

私は追加します:

7) マージは、DB 上のレコードの存在に応じて挿入または更新に変換されるため、更新と削除の楽観的同時実行を正しく処理しません。つまり、別のユーザーがレコードを同時に削除し、それを更新する場合、(1) 同時実行例外をスローする必要があります... しかし、そうではなく、レコードを新しいものとして挿入するだけです。

(1) 少なくとも、ほとんどの場合、私の意見では、そうすべきです。このユースケースで新しい挿入をトリガーしたいいくつかのケースを想像できますが、それらは通常とはかけ離れています。少なくとも、開発者には、「merge() == updateWithConcurrencyControl()」を受け入れるだけでなく、よく考えてもらいたいと思います。そうではないからです。

于 2014-12-08T17:29:17.843 に答える