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仕様では、カスケード持続に対してもこの動作が必要です。したがって、オブジェクトを削除しても、カスケード永続関係からそのオブジェクトへの参照を削除しないと、その削除は無視されます。
JPAを使用して論理削除を模倣しようとしていますか? –
@Vineet Reynolds - 本質的には、はい。アプリはモバイルクライアントと同期するため、レコードを保存しておき、クライアントに削除されたものを伝える必要があります。これを回避するには、削除されたタイムスタンプと共に別のテーブルで削除されたすべてのIDのリストを保持することで回避できますが、削除動作をオーバーライドして削除する代わりに物を隠す。 – aroth