session.Mergeとsession.SaveOrUpdateの違いは何ですか?


86

親/子オブジェクトまたは多対多の関係で、SaveOrUpdateまたはのいずれかを呼び出す必要があることに気付くことがありますMerge。通常、を呼び出す必要がある場合、呼び出すときにSaveOrUpdate発生する例外は、Merge最初に保存されていない一時オブジェクトに関係しています。

両者の違いを説明してください。

回答:


157

これはセクション10.7からです。Hibernateリファレンスドキュメントの自動状態検出

saveOrUpdate()は次のことを行います。

  • オブジェクトがこのセッションですでに永続的である場合は、何もしません
  • セッションに関連付けられている別のオブジェクトが同じ識別子を持っている場合は、例外をスローします
  • オブジェクトに識別子プロパティがない場合は、save()
  • オブジェクトの識別子に、新しくインスタンス化されたオブジェクトに割り当てられた値がある場合は、save()
  • オブジェクトが(<version>または<timestamp>によって)バージョン管理されており、バージョンプロパティ値が新しくインスタンス化されたオブジェクトに割り当てられた値と同じである場合、save()
  • それ以外の場合は、オブジェクトをupdate()します

そしてmerge()は非常に異なります:

  • 現在セッションに関連付けられているのと同じ識別子を持つ永続インスタンスがある場合は、指定されたオブジェクトの状態を永続インスタンスにコピーします
  • 現在セッションに関連付けられている永続インスタンスがない場合は、データベースからロードするか、新しい永続インスタンスを作成してみてください
  • 永続インスタンスが返されます
  • 指定されたインスタンスはセッションに関連付けられず、切り離されたままになります

ある時点でセッションから切り離されたオブジェクトを更新しようとしている場合、特に現在セッションに関連付けられているオブジェクトの永続インスタンスが存在する可能性がある場合は、Merge()を使用する必要があります。それ以外の場合、その場合にSaveOrUpdate()を使用すると、例外が発生します。


良い答え...私は疑問に思います-新しいエンティティでマージを使用する場合、あとがきを保存する理由はありますか、それともマージによってDBに新しいエンティティが確実に作成されたと見なすことができますか?(そして、それが切り離されたエンティティである場合、マージすると、変更は自動的にDBに省略されますか?)
Dani

5
あなたはこれについて確信を持っていますか?NHiberanteソースを見ると、SaveOrUpdateCopyは、Merge関数と同じパラメーターでMergeイベントをトリガーします。それらは同一だと思います。SaveOrUpdateCopy関数は1.0以降hibernate / nhibernateに存在していたもので、Merge関数は新しく、新しいJava標準に準拠するためにhibernateに追加されました(私は思う)
Torkel

5
@ Torkel-はとSaveOrUpdateCopy同じではありませんSaveOrUpdate。質問者Mergeが前者と後者のどちらを比較したいかはわかりません。SaveOrUpdateCopyは、Mergeインポートされる前にNHibernateでマージを行った現在は廃止されたメソッドです。
codekaizen 2011

知っておきたいこと... SaveOrUpdateはまだチュートリアルで頻繁に使用されています。
anael 2011

9

私はそれを理解するように、merge()現在のセッションに関連付けることがないかもしれないオブジェクトを取り、オブジェクトにその状態(等プロパティ値など)をコピーしているから、同じPK値/識別子(現在のセッションに関連付けられていますコース)。

saveOrUpdate()指定されたオブジェクトのID値に基づいて、セッションで保存または更新を呼び出します


4

SaveOrUpdateCopy()NHibernate3.1で非推奨になりました。Merge()代わりに使用する必要があります。


9
それだSaveOrUpdateCopyとマークされているObsolete、ではありませんSaveOrUpdate。この質問とその後の回答では、これら2つの異なる方法の間に多くの混乱があるようです。
codekaizen 2011

2
** Update()**

:-セッションに同じ識別子を持つ既に永続的なインスタンスが含まれていないことが確実な場合は、updateを使用してデータを休止状態で保存します

** Merge()**

:-セッションの状態を知らずにいつでも変更を保存したい場合は、hibernateでmerge()を使用してください。


1

私はこのタイプの例外を説明するかなり良い仕事をしたこのリンクを見つけました:

私のために働いたのは次のとおりです。

  1. マッピングMyclass.hbm.xmlファイルで、 cascade="merge"
  2. SaveOrUpdate 親オブジェクトに割り当てる前に、最初に子/依存オブジェクト。
  3. SaveOrUpdate 親オブジェクト。

ただし、このソリューションには制限があります。つまり、休止状態にするのではなく、子/依存オブジェクトの保存に注意する必要があります。

誰かがより良い解決策を持っているなら、私は見たいです。


-2
@Entity
@Table(name="emp")
public class Employee implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="emp_id")
    private int id;
    @Column(name="emp_name")
    private String name;
    @Column(name="salary")
    private int Salary;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSalary() {
        return Salary;
    }

    public void setSalary(int salary) {
        this.Salary = salary;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

public enum HibernateUtil {
    INSTANCE;
    HibernateUtil(){
        buildSessionFactory();
    }
    private SessionFactory sessionFactory=null;

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    private  void buildSessionFactory() {
        Configuration configuration = new Configuration();

        configuration.addAnnotatedClass (TestRefresh_Merge.Employee.class);
        configuration.setProperty("connection.driver_class","com.mysql.jdbc.Driver");
        configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/hibernate");                                
        configuration.setProperty("hibernate.connection.username", "root");     
        configuration.setProperty("hibernate.connection.password", "root");
        configuration.setProperty("dialect", "org.hibernate.dialect.MySQLDialect");
        configuration.setProperty("hibernate.hbm2ddl.auto", "update");
        configuration.setProperty("hibernate.show_sql", "true");
        configuration.setProperty(" hibernate.connection.pool_size", "10");
        /* configuration.setProperty(" hibernate.cache.use_second_level_cache", "true");
         configuration.setProperty(" hibernate.cache.use_query_cache", "true");
         configuration.setProperty(" cache.provider_class", "org.hibernate.cache.EhCacheProvider");
         configuration.setProperty("hibernate.cache.region.factory_class" ,"org.hibernate.cache.ehcache.EhCacheRegionFactory");
        */
        // configuration
        StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
           sessionFactory = configuration.buildSessionFactory(builder.build());
           setSessionFactory(sessionFactory);
    }

    public  static SessionFactory getSessionFactoryInstance(){
        return INSTANCE.getSessionFactory();
    }
} 


public class Main {
    public static void main(String[] args) {
        HibernateUtil util=HibernateUtil.INSTANCE;
        SessionFactory factory=util.getSessionFactory();
        //save(factory); 
        retrieve(factory);
    }

     private static void retrieve(SessionFactory factory) {
        Session sessionOne=factory.openSession();

        Employee employee=(Employee)sessionOne.get(Employee.class, 5);

        sessionOne.close(); // detached Entity

        employee.setName("Deepak1");

        Session sessionTwo=factory.openSession();

        Employee employee1=(Employee)sessionTwo.get(Employee.class, 5);
        sessionTwo.beginTransaction();
        sessionTwo.saveOrUpdate(employee); // it will throw exception

        //sessionTwo.merge(employee); // it will work

        sessionTwo.getTransaction().commit();

        sessionTwo.close();

    }

    private static void save(SessionFactory factory) {
        Session sessionOne=factory.openSession();
        Employee emp=new Employee();
        emp.setName("Abhi");
        emp.setSalary(10000);
        sessionOne.beginTransaction();
        try{

            sessionOne.save(emp);
            sessionOne.getTransaction().commit();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            sessionOne.close();
        }

    }
}

2
回答を編集して、影響を受けるコードを表示することを検討してから、最後に完全なコードダンプを検討する必要があります。現状では、下にスクロールしてコメントを横切る必要があります。回答方法を参照してください。
バグ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.