2011-07-11 20 views
16

質問のタイトルは基本的にすべてそれを言います。 JPA/Hibernateでを正常にデータベースからのエンティティの削除を防ぐことは可能ですか?私が望むのは、実際にそれを削除するのではなく、そのエンティティに「隠し」のフラグを立てることです。JPA/Hibernate - PreRemoveハンドラでの削除を防止しますか?

また、他のエンティティのコレクションを所有するエンティティを削除しようとすると、所有エンティティとそのコレクション内のすべてのエンティティが余分な作業なしで非表示としてマークされるように、Cascadeセマンティクスを保持します。削除を防ぎ、エンティティを隠しとしてマークするハンドラを実装することを超えて、自分自身で必要なものです。

これは可能ですか、それとも他のアプローチを考え出す必要がありますか?

+0

JPAを使用して論理削除を模倣しようとしていますか? –

+0

@Vineet Reynolds - 本質的には、はい。アプリはモバイルクライアントと同期するため、レコードを保存しておき、クライアントに削除されたものを伝える必要があります。これを回避するには、削除されたタイムスタンプと共に別のテーブルで削除されたすべてのIDのリストを保持することで回避できますが、削除動作をオーバーライドして削除する代わりに物を隠す。 – aroth

答えて

12

JPA/Hibernateでは、エンティティのデータベースからの削除を正常に防止できますか?

はい、EntityManager.remove(entity)を使用しない限り、これが可能です。 EntityManager.remove()を使用すると、JPAプロバイダは対応するSQL DELETE文を使用して削除対象のオブジェクトにフラグを立て、オブジェクトを削除フラグを立てるとエレガントな解決策を実行できなくなることを意味します。

Hibernateでは、@SQLDelete and @Where annotationsを使用してこれを達成できます。しかし、EntityManager.find()@Where注釈で指定されているフィルタを無視することが知られているため、JPAではうまくいきません。

したがって、JPAのみの解決策は、データベース内の論理的に削除されたエンティティを「生きた」エンティティと区別するために、エンティティクラスにフラグ、すなわち列を追加することを含む。論理的に削除されたエンティティが結果セットで使用できないようにするには、適切なクエリ(JPQLとネイティブ)を使用する必要があります。​​注釈と@PrePersist注釈を使用してエンティティライフサイクルイベントをフックして、フラグが永続イベントと更新イベントで更新されるようにすることができます。ここでも、EntityManager.removeメソッドを呼び出さないようにする必要があります。

私は、エンティティの除去のためにトリガーされるライフサイクルイベントにフックする@PreRemove注釈を使用して提案しますが、削除を防ぐために、エンティティ・リスナーを使用すると、以下に述べる理由のためにトラブルをはらんでいるだろう。

  • 論理意味でSQL DELETEが発生しないようにする必要がある場合は、オブジェクトを同じトランザクションに維持して、*を再作成する必要があります。唯一の問題は、EntityListener内のEntityManagerを参照するのは適切な設計上の決定ではなく、推論によってリスナー内でEntityManager.persistを呼び出すことです。その根拠は非常に単純です。がEntityListenerで別のEntityManager参照を取得することになり、アプリケーションであいまいで混乱している動作になります。
  • トランザクション自体の中のSQL DELETEが発生しないようにする必要がある場合は、EntityListenerに例外をスローする必要があります。これは通常、トランザクションをロールバックして終了します(特に、Exceptionがロールバックを引き起こすものと宣言されているRuntimeExceptionまたはアプリケーション例外の場合)。また、トランザクション全体がロールバックされるため、何のメリットもありません。

あなたはEclipseLinkの代わりに休止状態を使用するオプションを持っている場合、あなたがDescriptorCustomizer適切かAdditionalCriteria注釈を使用してを定義する場合、エレガントな解決策が可能であることが表示されます。これらの両方は、EntityManager.removeとの呼び出しでうまくいくように見えます。ただし、論理的に削除されたエンティティのアカウントにJPQLまたはネイティブクエリーを記述する必要があります。 *


これはJPA Wikibook on the topic of cascading Persistに概説されている:

あなたは、それを削除したためにオブジェクトを削除するには、そのオブジェクトに持続呼び出す場合、それはオブジェクトを復活し、それならば再び永続的になります。これが意図的である場合は望ましいかもしれませんが、JPA仕様では、カスケード持続に対してもこの動作が必要です。したがって、オブジェクトを削除しても、カスケード永続関係からそのオブジェクトへの参照を削除しないと、その削除は無視されます。

+0

ああ、私は 'EntityManager.remove()'を使って動作させることを期待していました。しかし、あなたが言うように、リスナーに適切な 'EntityManager'インスタンスを取得する信頼できる方法はありません。あなたが提案し、削除したものをアップデートに置き換えて、それが働いている限り、私は長い道のりを歩んできました。しかし、私はJPAがこのユースケースに対してより洗練された解決策を許して欲しいと思っています。 – aroth

+0

はい、em.remove()をネイティブSQLクエリまたはJPQLステートメントにマッピングできるように、JPAにはより洗練されたソリューションを組み込む必要があります。このカスタム動作は適切な場所に指定してください。エンティティ上、または他の場所で –

関連する問題