JPA EntityManager:merge()ではなくpersist()を使用する理由


951

EntityManager.merge() 新しいオブジェクトを挿入し、既存のオブジェクトを更新できます。

なぜ使用したいのですかpersist()(新しいオブジェクトしか作成できません)?



2
図が好きなら。:この参照してくださいspitballer.blogspot.in/2010/04/...
RBZ

回答:


1615

どちらの方法でも、エンティティをPersistenceContextに追加します。違いは、エンティティを後でどのように処理するかです。

Persistはエンティティインスタンスを取得してコンテキストに追加し、そのインスタンスを管理します(つまり、エンティティへの将来の更新が追跡されます)。

Mergeは、状態がマージされたマネージインスタンスを返します。PersistenceContextに存在するものを返すか、エンティティの新しいインスタンスを作成します。いずれの場合も、提供されたエンティティから状態をコピーし、マネージドコピーを返します。渡したインスタンスは管理されません(変更を加えても、mergeを再度呼び出さない限り、トランザクションの一部にはなりません)。返されたインスタンス(マネージドインスタンス)を使用できます。

たぶん、コード例が役立つでしょう。

MyEntity e = new MyEntity();

// scenario 1
// tran starts
em.persist(e); 
e.setSomeField(someValue); 
// tran ends, and the row for someField is updated in the database

// scenario 2
// tran starts
e = new MyEntity();
em.merge(e);
e.setSomeField(anotherValue); 
// tran ends but the row for someField is not updated in the database
// (you made the changes *after* merging)

// scenario 3
// tran starts
e = new MyEntity();
MyEntity e2 = em.merge(e);
e2.setSomeField(anotherValue); 
// tran ends and the row for someField is updated
// (the changes were made to e2, not e)

シナリオ1と3はほぼ同じですが、シナリオ2を使用したい場合があります。


3
@dma_k:Hibernateを使用しているようです。私はJPAよりもHibernateに精通していませんが、JPAでEntityManager.persist()を呼び出して分離されたエンティティを渡すと、a)EntityExistsExceptionをすぐに取得するか、b)フラッシュ/コミット時に別のPersistenceExceptionを取得します。多分私はここの質問を誤解しましたか?
Mike

49
この回答は、マージ/永続化されるエンティティが永続コンテキストにすでに存在する場合もカバーする場合は改善される可能性があります(または永続化/マージされたエンティティがまだ存在しない場合の動作のみを説明することを少なくとも明確にしました)
ヘンリー

2
1つの方法の方がパフォーマンスが高いですか?おそらくmerge、オブジェクトを管理する前の完全なコピーがパフォーマンスに影響を与えるでしょうか?
ケビンメレディス

2
IDはどうですか?私が持っている場合は@GeneratedId、私はシナリオ2でそれを得ることができますか?
rascio 2014年

7
マイク:「マージは新しいインスタンスを作成します...」:これは常に正しいとは限りません。EntityManagerは、そのコンテキストで既に管理されているエンティティを検出すると、(フィールドを更新した後)このインスタンスを返します。回答を編集してください。投票します。
Heri

181

永続化とマージは2つの異なる目的で使用されます(それらはまったく代替手段ではありません)。

(差異情報を拡張するために編集)

持続:

  • 新しいレジスタをデータベースに挿入します
  • オブジェクトをエンティティマネージャーにアタッチします。

マージ:

  • 同じIDの添付オブジェクトを見つけて更新します。
  • 存在する場合は、すでにアタッチされているオブジェクトを更新して返します。
  • 存在しない場合は、新しいレジスタをデータベースに挿入します。

persist()効率:

  • 新しいレジスタをデータベースに挿入するには、merge()よりも効率的です。
  • 元のオブジェクトは複製されません。

persist()セマンティクス:

  • これは、誤って挿入して更新していないことを確認します。

例:

{
    AnyEntity newEntity;
    AnyEntity nonAttachedEntity;
    AnyEntity attachedEntity;

    // Create a new entity and persist it        
    newEntity = new AnyEntity();
    em.persist(newEntity);

    // Save 1 to the database at next flush
    newEntity.setValue(1);

    // Create a new entity with the same Id than the persisted one.
    AnyEntity nonAttachedEntity = new AnyEntity();
    nonAttachedEntity.setId(newEntity.getId());

    // Save 2 to the database at next flush instead of 1!!!
    nonAttachedEntity.setValue(2);
    attachedEntity = em.merge(nonAttachedEntity);

    // This condition returns true
    // merge has found the already attached object (newEntity) and returns it.
    if(attachedEntity==newEntity) {
            System.out.print("They are the same object!");
    }

    // Set 3 to value
    attachedEntity.setValue(3);
    // Really, now both are the same object. Prints 3
    System.out.println(newEntity.getValue());

    // Modify the un attached object has no effect to the entity manager
    // nor to the other objects
    nonAttachedEntity.setValue(42);
}

この方法では、エンティティマネージャーのレジスターに1つの添付オブジェクトのみが存在します。

idを持つエンティティのmerge()は次のようなものです:

AnyEntity myMerge(AnyEntity entityToSave) {
    AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId());
    if(attached==null) {
            attached = new AnyEntity();
            em.persist(attached);
    }
    BeanUtils.copyProperties(attached, entityToSave);

    return attached;
}

MySQLのmerge()に接続すると、ON DUPLICATE KEY UPDATEオプションを指定したINSERTの呼び出しを使用したpersist()と同じくらい効率的ですが、JPAは非常に高水準のプログラミングであり、これがどこでも当てはまるとは限りません。


あなたはそれが交換するために有効ではありません場合は名前を付けることができますem.persist(x)ではx = em.merge(x)
アーロンディグラ2013年

20
persist()はEntityExistsExceptionをスローできます。コードがデータの更新ではなく挿入を実行していることを確認したい場合は、永続化する必要があります。
Josep Panadero 2013年

1
merge()スローすることもできますEntityExistsException
Sean

1
@なし可能性があります。これはであるためですがRuntimeException、Javadocには記載されていません。
マーティン

154

割り当てられたジェネレーターを使用している場合、persistの代わりにmergeを使用すると、冗長なSQLステートメントが発生し、パフォーマンスに影響を与える可能性があります

また、マネージエンティティはHibernateによって自動的に管理され、その状態はPersistence Contextのフラッシュ時にダーティチェックメカニズムによってデータベースレコードと同期されるため、マネージエンティティのマージの呼び出しも誤りです。

これらすべてがどのように機能するかを理解するには、まず、Hibernateが開発者の考え方をSQLステートメントからエンティティの状態遷移にシフトすることを知っておく必要があります。

エンティティがHibernateによってアクティブに管理されると、すべての変更が自動的にデータベースに伝達されます。

Hibernateは現在接続されているエンティティを監視します。ただし、エンティティが管理対象になるには、適切なエンティティ状態である必要があります。

JPAの状態遷移をよりよく理解するために、次の図を視覚化できます。

JPAエンティティの状態遷移

または、Hibernate固有のAPIを使用する場合:

Hibernateエンティティの状態遷移

上の図に示すように、エンティティは次の4つの状態のいずれかになります。

  • 新規(一時的)

    Hibernate Session(aka Persistence Context)に関連付けられておらず、データベーステーブル行にマップされていない、新しく作成されたオブジェクトは、新規(一時的)状態と見なされます。

    永続化するには、EntityManager#persistメソッドを明示的に呼び出すか、推移的永続化メカニズムを利用する必要があります。

  • 永続的(管理)

    永続エンティティはデータベーステーブルの行に関連付けられており、現在実行中の永続コンテキストによって管理されています。このようなエンティティに加えられた変更はすべて検出され、データベースに伝達されます(セッションのフラッシュ時)。Hibernateを使用すると、INSERT / UPDATE / DELETEステートメントを実行する必要がなくなります。Hibernateはトランザクション後書き作業スタイルを採用しており、変更は現在のSessionフラッシュ時間中の最後の責任ある瞬間に同期されます。

  • 戸建

    現在実行中の永続コンテキストが閉じられると、以前に管理されていたすべてのエンティティが切り離されます。継続的な変更は追跡されなくなり、自動データベース同期は行われません。

    デタッチされたエンティティをアクティブなHibernateセッションに関連付けるには、次のオプションのいずれかを選択できます。

    • 再接続

      Hibernate(JPA 2.1ではない)は、Session#updateメソッドを介した再接続をサポートしています。Hibernateセッションは、特定のデータベース行に対して1つのEntityオブジェクトのみを関連付けることができます。これは、永続コンテキストがメモリ内キャッシュ(1次レベルキャッシュ)として機能し、1つの値(エンティティ)のみが特定のキー(エンティティタイプとデータベース識別子)に関連付けられているためです。エンティティを再接続できるのは、現在のHibernateセッションにすでに関連付けられている(同じデータベース行に一致する)他のJVMオブジェクトがない場合のみです。

    • マージ

    マージにより、分離されたエンティティの状態(ソース)が管理対象エンティティのインスタンス(宛先)にコピーされます。現在のセッションにマージするエンティティに同等のものがない場合、データベースから1つがフェッチされます。デタッチされたオブジェクトインスタンスは、マージ操作後もデタッチされたままになります。

  • 削除されました

    JPAは管理対象エンティティのみを削除することを要求していますが、Hibernateは分離されたエンティティを削除することもできます(ただし、Session#deleteメソッド呼び出しによってのみ)。削除されたエンティティは削除のみがスケジュールされ、実際のデータベースのDELETEステートメントはセッションのフラッシュ時に実行されます。



@gstackoverflowあなたが得た答えは正しいものです。詳細については、この記事または私の著書「ハイパフォーマンスJavaパーシスタンス」をチェックしてください
Vlad Mihalcea 2017

したがって、orphanremoval = trueの操作順序を変更する可能性はありませんか?
gstackoverflow

通常の場合の操作順序に関する記事。特定の私の質問orphanRemovalに
gstackoverflow

1
そのような図で休止状態を説明することは不可能です。デタッチ後にセッションをフラッシュできないのはなぜですか?すでに永続化されているエンティティを保存しようとするとどうなりますか?保存と永続化に関して、フラッシュの動作が異なるのはなぜですか?このような質問は1000ありますが、明確な論理はありません。
GingerBeer 2018年

37

JPAが生成するフィールドがない場合でもem.merge、を使用すると、SELECTごとINSERTにステートメントが表示されることに気付きました。主キーフィールドは自分で設定したUUIDでした。私はそれに切り替えてem.persist(myEntityObject)、ちょうどINSERTステートメントを得ました。


3
IDを割り当て、JPAコンテナーはどこから取得したのかわからないため、理にかなっています。たとえば、複数のアプリケーションが同じデータベースに書き込むシナリオでは、オブジェクトがデータベースにすでに存在している可能性があります。
アーロンディグラ

で同様の問題が発生しましたmerge()。複雑なビューを持つPostgreSQLデータベースがありました。ビューはいくつかのテーブルからのデータを集計しました(テーブルの構造は同じですが、名前が異なります)。したがって、JPAはを試行しましたがmerge()、実際にはJPAが最初に作成されSELECT(ビュー設定が原因でデータベースが異なるテーブルから同じ主キーを持つ複数のレコードを返す可能性がありました!)、次にJPA(Hibernateが実装)が失敗しました:同じキーを持つ複数のレコードがあります(org.hibernate.HibernateException: More than one row with the given identifier was found)。私の場合persist()、私を助けました。
flaz14 2016年

29

JPA仕様では、について次のように述べられていますpersist()

場合Xは分離オブジェクトで、EntityExistsException操作が呼び出された、または持続ときスローされるEntityExistsException、または別のPersistenceExceptionフラッシュでスロー又は時間をコミットすることができます。

そのpersist()ため、オブジェクトが分離されたオブジェクトであってはならない場合に使用するのが適切です。あなたはコードにスローさせることを好むかもしれませんPersistenceExceptionようにして、速く失敗ようにすることもできます。

が、仕様が不明であるpersist()設定するかもしれません@GeneratedValue @Idオブジェクトのために。merge()ただし、@Id生成済みのオブジェクトが必要です。


5
「のための+1 merge()が持つオブジェクト持っている必要があり@Id 、既に生成されたが」。EntityManagerがオブジェクトIDのフィールドの値を見つけられない場合は常に、DBに永続化(挿入)されます。
Omar

私は州を明確にしていないので、これを最初に理解しませんでした。これが私と同じように誰かを助けることを願っています。docs.jboss.org/hibernate/core/3.6/reference/en-US/html/...
RBZ

1
@GeneratedValueはmerge()とpersist()に異なる影響を与えません
SandeepGodara

17

永続的なマージを使用するのに役立つマージに関する詳細:

元のエンティティ以外のマネージドインスタンスを返すことは、マージプロセスの重要な部分です。同じ識別子を持つエンティティインスタンスが永続化コンテキストに既に存在する場合、プロバイダーはその状態をマージされるエンティティの状態で上書きしますが、既存の管理対象バージョンをクライアントに返して、中古。プロバイダーが永続コンテキストでEmployeeインスタンスを更新しなかった場合、そのインスタンスへの参照は、マージされる新しい状態と一致しなくなります。

merge()が新しいエンティティで呼び出されると、persist()操作と同様に動作します。エンティティを永続化コンテキストに追加しますが、元のエンティティインスタンスを追加する代わりに、新しいコピーを作成してそのインスタンスを管理します。merge()操作によって作成されたコピーは、persist()メソッドが呼び出された場合と同様に永続化されます。

関係が存在する場合、merge()操作は、分離されたエンティティによって参照されるエンティティの管理されたバージョンを指すように管理されたエンティティを更新しようとします。エンティティに永続的なIDのないオブジェクトとの関係がある場合、マージ操作の結果は未定義です。プロバイダーによっては、マネージドコピーが非永続オブジェクトをポイントすることを許可する場合と、例外をすぐにスローする場合があります。これらの場合、オプションでmerge()操作をカスケードして、例外の発生を防ぐことができます。このセクションの後半で、merge()操作のカスケードについて説明します。マージされているエンティティが削除されたエンティティを指している場合、IllegalArgumentException例外がスローされます。

遅延読み込みの関係は、マージ操作の特殊なケースです。エンティティがデタッチされる前に遅延読み込み関係がトリガーされなかった場合、エンティティがマージされるときにその関係は無視されます。関係が管理中にトリガーされ、エンティティがデタッチされている間にnullに設定された場合、管理されているバージョンのエンティティも同様に、マージ中に関係がクリアされます。

上記の情報はすべて、Mike KeithとMerrick Schnicariolによる「Pro JPA 2 Mastering the Java™Persistence API」から引用したものです。第6章セクションの分離とマージ。この本は、実際には著者によってJPAに捧げられた2番目の本です。この新しい本には、以前のものよりも多くの新しい情報が含まれています。私は本書をJPAに真剣に関与する人のために読むことを本当にお勧めします。最初の回答を匿名で投稿して申し訳ありません。


17

との間にはさらにいくつかの違いがmergeありますpersist(ここですでに投稿されているものをもう一度列挙します)。

D1。merge渡されたエンティティを管理するのではなく、管理される別のインスタンスを返します。persist反対側では、渡されたエンティティを管理します。

//MERGE: passedEntity remains unmanaged, but newEntity will be managed
Entity newEntity = em.merge(passedEntity);

//PERSIST: passedEntity will be managed after this
em.persist(passedEntity);

D2。エンティティを削除してから、そのエンティティを永続化することにした場合は、mergeがスローされるため、persist()を使用してのみそれを実行できますIllegalArgumentException

D3。IDを手動で管理することを決定した場合(UUIDを使用するなど)、そのIDを持つ既存のエンティティーを探すために、merge 後続のSELECTクエリがトリガーされますが、persistそれらのクエリは必要ない場合があります。

D4。コードを呼び出すコードを単に信頼しない場合があり、データが更新されずに挿入されることを確認するには、を使用する必要がありますpersist


8

セッション中の遅延ロードされたコレクションにアクセスしようとしたため、エンティティでlazyLoading例外が発生していました。

別のリクエストで、セッションからエンティティを取得し、jspページのコレクションにアクセスしようとして問題がありました。

これを軽減するために、コントローラーで同じエンティティを更新してjspに渡しましたが、セッションで再保存すると、アクセス可能でありSessionScopeLazyLoadingException例2の変更であるをスローしないことを想像しました。

以下は私のために働いています:

// scenario 2 MY WAY
// tran starts
e = new MyEntity();
e = em.merge(e); // re-assign to the same entity "e"

//access e from jsp and it will work dandy!!

7

使用例が含まれているため、Hibernateドキュメントからこの説明がわかりました。

merge()の使用法とセマンティクスは、新規ユーザーを混乱させるようです。まず、あるエンティティマネージャーに読み込まれたオブジェクトの状態を別の新しいエンティティマネージャーで使用しない限りmerge()をまったく使用する必要はありませ。一部のアプリケーション全体では、この方法を使用しません。

通常、merge()は次のシナリオで使用されます。

  • アプリケーションは最初のエンティティーマネージャーにオブジェクトをロードします
  • オブジェクトはプレゼンテーション層に渡されます
  • オブジェクトにいくつかの変更が加えられています
  • オブジェクトはビジネスロジックレイヤーに渡されます。
  • アプリケーションは、2番目のエンティティマネージャーでmerge()を呼び出すことにより、これらの変更を永続化します

次に、merge()の正確なセマンティクスを示します。

  • 現在永続コンテキストに関連付けられている同じ識別子を持つマネージドインスタンスがある場合は、指定されたオブジェクトの状態をマネージドインスタンスにコピーします
  • 現在永続コンテキストに関連付けられているマネージドインスタンスがない場合は、データベースからロードするか、新しいマネージドインスタンスを作成してください
  • マネージドインスタンスが返されます
  • 指定されたインスタンスは永続化コンテキストに関連付けられず、デタッチされたままであり、通常は破棄されます

送信元http : //docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html


6

答えを調べてみると、 `Cascade 'とID生成に関していくつかの詳細が欠けています。 質問を見る

また、あなたが別の持つことができることを言及する価値があるCascadeマージと持続のための注釈を:Cascade.MERGECascade.PERSISTいるが、使用される方法に従って処理されます。

仕様はあなたの友達です;)


6

JPAは、間違いなく、Javaプラットフォーム上に構築されたエンタープライズアプリケーションのドメインにおける優れた単純化です。J2EEの古いエンティティBeanの複雑さに対処しなければならなかった開発者として、Java EE仕様にJPAを含めることは大きな前進であると私は思います。しかし、JPAの詳細をさらに掘り下げていくと、それほど簡単ではないことがわかります。この記事では、EntityManagerのmergeメソッドとpersistメソッドの比較について扱います。これらのメソッドの重複動作は、初心者だけでなく混乱を招く可能性があります。さらに、両方の方法を、より一般的な方法の特殊なケースを組み合わせたものと見なす一般化を提案します。

永続エンティティ

mergeメソッドとは対照的に、persistメソッドはかなり単純で直感的です。持続メソッドの使用の最も一般的なシナリオは、次のように要約できます。

「新しく作成されたエンティティークラスのインスタンスは、persistメソッドに渡されます。このメソッドが返された後、エンティティーは管理され、データベースへの挿入が計画されています。エンティティがPERSISTカスケード戦略でマークされた関係を介して別のエンティティを参照する場合、この手順もそれに適用されます。」

ここに画像の説明を入力してください

仕様はより詳細になりますが、これらの詳細は多かれ少なかれエキゾチックな状況のみを対象としているため、それらを覚えておくことは重要ではありません。

エンティティのマージ

永続化と比較すると、マージの動作の説明はそれほど単純ではありません。永続化の場合のように、主なシナリオはありません。プログラマは、正しいコードを書くためにすべてのシナリオを覚えておく必要があります。JPAデザイナーは、分離されたエンティティを処理することを主な関心事とするいくつかのメソッドを望んでいるようです(新しく作成されたエンティティを主に処理する永続メソッドとは反対に)。マージメソッドの主なタスクは、非永続エンティティ(引数として渡されます)を、永続コンテキスト内の対応する管理対象に渡します。ただし、このタスクはさらにいくつかのシナリオに分かれ、メソッド全体の動作の理解度を低下させます。

JPA仕様の段落を繰り返す代わりに、マージメソッドの動作を概略的に示すフロー図を用意しました。

ここに画像の説明を入力してください

では、永続化を使用する必要があるのはいつですか?

固執する

  • メソッドが常に新しいエンティティを作成し、エンティティを更新しないようにする必要があります。それ以外の場合、メソッドは主キーの一意性違反の結果として例外をスローします。
  • エンティティをステートフルな方法で処理するバッチプロセス(ゲートウェイパターンを参照)。
  • パフォーマンスの最適化

マージ

  • このメソッドでは、データベースにエンティティを挿入または更新します。
  • エンティティをステートレスな方法で処理したい(サービスのデータ転送オブジェクト)
  • まだ作成されていない可能性がある別のエンティティへの参照を持つ可能性がある新しいエンティティを挿入したい(関係はMERGEとマークされている必要がある)。たとえば、新しいアルバムまたは既存のアルバムへの参照を含む新しい写真を挿入します。

EマネージドとPCにはEのマネージドバージョンが含まれていますか?
GingerBeer

5

シナリオX:

Table:Spitter(One)、Table:Spittles(Many)(SpittlesはFK:spitter_idとの関係の所有者です)

このシナリオでは、保存が行われます。Spitterと両方のSpittlesが、Same Spitterによって所有されているかのように保存されます。

        Spitter spitter=new Spitter();  
    Spittle spittle3=new Spittle();     
    spitter.setUsername("George");
    spitter.setPassword("test1234");
    spittle3.setSpittle("I love java 2");       
    spittle3.setSpitter(spitter);               
    dao.addSpittle(spittle3); // <--persist     
    Spittle spittle=new Spittle();
    spittle.setSpittle("I love java");
    spittle.setSpitter(spitter);        
    dao.saveSpittle(spittle); //<-- merge!!

シナリオY:

これは、Spitterを保存し、2つのSpittlesを保存しますが、同じSpitterを参照しません。

        Spitter spitter=new Spitter();  
    Spittle spittle3=new Spittle();     
    spitter.setUsername("George");
    spitter.setPassword("test1234");
    spittle3.setSpittle("I love java 2");       
    spittle3.setSpitter(spitter);               
    dao.save(spittle3); // <--merge!!       
    Spittle spittle=new Spittle();
    spittle.setSpittle("I love java");
    spittle.setSpitter(spitter);        
    dao.saveSpittle(spittle); //<-- merge!!

1
Spitterは、Graig Walls著の「Spring in Action」第3版から引用したオブジェクトです。Spittersは何かを言う人で、Spittleは実際に言っていることです。したがって、Spitterには多くのスピッターがあり、これは彼がストリングのリストを持っていることを意味します。
ジョージPapatheodorou 2013年

1
Spring in Actionを読まなくても少し読みやすい例を使用できます...
wonderb0lt

1
Spitterがテーブルであることを書かれている上に、spitterが所有する別のテーブルであるので、唾やspitterが何であるかを知っているあなた、実際のdont必要。これとその...
ジョージPapatheodorou

3

別の観察:

merge()このようなIDのレコードがテーブルに既に存在する場合にのみ、自動生成されたID(IDENTITYおよびでテストSEQUENCE)が考慮されます。その場合merge()、レコードを更新しようとします。ただし、IDがないか、既存のレコードと一致しない場合は、ID merge()を完全に無視して、新しいID を割り当てるようにデータベースに要求します。これは、多くのバグの原因になることがあります。merge()新しいレコードのIDを強制するために使用しないでください。

persist()一方、IDを渡すことさえできません。すぐに失敗します。私の場合、それは:

原因:org.hibernate.PersistentObjectException:永続化に渡された分離エンティティ

hibernate-jpa javadocにヒントがあります:

例外:javax.persistence.EntityExistsException-エンティティがすでに存在する場合。(エンティティがすでに存在する場合、永続化操作が呼び出されたときにEntityExistsExceptionがスローされるか、フラッシュ時またはコミット時にEntityExistsExceptionまたは別のPersistenceExceptionがスローされる場合があります。)


2
自動生成されたIDを使用していない場合は、新しいエンティティに手動でIDを指定する必要があります。persist()IDがあることについて文句を言うのではなく、同じIDを持つ何かがすでにデータベースにある場合に文句を言うだけです。
時間

1

永続化をいつ使用、いつマージを使用するかについてのアドバイスがここにあるかもしれません。それは状況に依存すると思います。新しいレコードを作成する必要がある可能性と、永続化されたデータを取得するのがどれほど難しいかです。

自然なキー/識別子を使用できると仮定しましょう。

  • データは永続化する必要がありますが、たまにレコードが存在し、更新が必要です。この場合、永続化を試すことができ、それがEntityExistsExceptionをスローする場合は、それを調べてデータを結合します。

    {entityManager.persist(entity)}を試してください

    catch(EntityExistsException exception){/ *取得してマージ* /}

  • 永続化されたデータを更新する必要がありますが、データの記録がまだない場合があります。この場合、それを調べ、エンティティが見つからない場合は永続化します。

    entity = entityManager.find(key);

    if(entity == null){entityManager.persist(entity); }

    それ以外の場合は{/ *マージ* /}

自然なキー/識別子がない場合、エンティティが存在するかどうか、またはどのように検索するかを判断するのが難しくなります。

マージも2つの方法で処理できます。

  1. 通常、変更が小さい場合は、管理対象エンティティに変更を適用します。
  2. 変更が一般的である場合は、永続化されたエンティティからIDをコピーし、変更されていないデータもコピーします。次に、EntityManager :: merge()を呼び出して、古いコンテンツを置き換えます。

0

それらをDBに追加するには、persist(entity)をまったく新しいエンティティで使用する必要があります(エンティティがDBにすでに存在する場合は、EntityExistsExceptionがスローされます)。

merge(entity)を使用して、エンティティがデタッチされて変更された場合にエンティティを永続コンテキストに戻す必要があります。

おそらく永続化はINSERT SQLステートメントとマージUPDATE SQLステートメントを生成しています(しかし、私にはわかりません)。


これは誤りです。新しいeでmerge(e)を呼び出す場合は、永続化する必要があります。
PedroLamarão2015


JPA仕様バージョン2.1、セクション3.2.7.1、2番目の箇条書きから:「Xが新しいエンティティインスタンスである場合、新しい管理エンティティインスタンスX 'が作成され、Xの状態が新しい管理エンティティインスタンスX'にコピーされます。」
PedroLamarão15年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.