Detached entity passed to persistからJPA Entity Management:Why use persist()over merge()まで?

4110 ワード

今日テストで通知機能を追加したとき、detached entity passed to persistエラーが報告されました.なぜなら、通知をデータベースに保存するとき、通知にはuserオブジェクトを設定する必要があり、渡されたuserオブジェクトは遊離状態のオブジェクトであり、私の通知クラスでは
@ManyToOne(cascade = {CascadeType.MERGE,CascadeType.REFRESH,CascadeType.PERSIST},optional = false)
private User source; // 

後改成
@ManyToOne(cascade = {CascadeType.MERGE,CascadeType.REFRESH},optional = false)
private User source; // 

つまりカスケード保存を外して問題が解決しました
後でカスケード保存を外さずにデータベースから永続化オブジェクトを見つけてnotificationオブジェクトを埋め込むことも成功
notification.setSource(userRepository.findOne(source.getId()));
notificationRepository.save(notification);

jpaのpersist()メソッドとmerge()メソッドの違いは何ですか?良い解釈が見つかりました
抜粋して後で調べるのに便利だ
persist:
  • Insert a new register to the database
  • Attach the object to the entity manager.

  • merge:
  • Find an attached object with the same id and update it.
  • If exists update and return the already attached object.
  • If doesn't exist insert the new register to the database.

  • persist() efficiency:
  • It could be more efficient for inserting a new register to a database than merge().
  • It doesn't duplicates the original object.

  • persist() semantics:
  • It makes sure that you are inserting and not updating by mistake.

  • エンティティのステータス
  • New (Transient) A newly created object that hasn’t ever been associated with a Hibernate  Session  (a.k.a  Persistence Context ) and is not mapped to any database table row is considered to be in the New (Transient) state. To become persisted we need to either explicitly call the  EntityManager#persist  method or make use of the transitive persistence mechanism.
  • Persistent (Managed) A persistent entity has been associated with a database table row and it’s being managed by the current running Persistence Context. Any change made to such entity is going to be detected and propagated to the database (during the Session flush-time). With Hibernate, we no longer have to execute INSERT/UPDATE/DELETE statements. Hibernate employs a transactional write-behind working style and changes are synchronized at the very last responsible moment, during the current  Session  flush-time.
  • Detached Once the current running Persistence Context is closed all the previously managed entities become detached. Successive changes will no longer be tracked and no automatic database synchronization is going to happen. To associate a detached entity to an active Hibernate Session, you can choose one of the following options:
  • Reattaching Hibernate (but not JPA 2.1) supports reattaching through the Session#update method. A Hibernate Session can only associate one Entity object for a given database row. This is because the Persistence Context acts as an in-memory cache (first level cache) and only one value (entity) is associated to a given key (entity type and database identifier). An entity can be reattached only if there is no other JVM object (matching the same database row) already associated to the current Hibernate Session.
  • Merging

  • The merge is going to copy the detached entity state (source) to a managed entity instance (destination). If the merging entity has no equivalent in the current Session, one will be fetched from the database. The detached object instance will continue to remain detached even after the merge operation.
  • Removed Although JPA demands that managed entities only are allowed to be removed, Hibernate can also delete detached entities (but only through a Session#delete method call). A removed entity is only scheduled for deletion and the actual database DELETE statement will be executed during Session flush-time.

  • To understand the JPA state transitions better, you can visualize the following diagram:
    Or if you use the Hibernate specific API:
    回答者は自分の書いた本も出してくれましたが、https://vladmihalcea.com/tutorials/hibernate/