Apa perbedaan antara session.Merge dan session.SaveOrUpdate?

87

Saya perhatikan terkadang dengan objek orang tua / anak saya atau hubungan banyak ke banyak, saya perlu memanggil salah satu SaveOrUpdateatau Merge. Biasanya, ketika saya perlu menelepon SaveOrUpdate, pengecualian yang saya dapatkan saat menelepon Mergeberkaitan dengan objek sementara yang tidak disimpan terlebih dahulu.

Tolong jelaskan perbedaan antara keduanya.

EvilSyn
sumber

Jawaban:

158

Ini dari bagian 10.7. Deteksi status otomatis dari Dokumentasi Referensi Hibernasi:

saveOrUpdate () melakukan hal berikut:

  • jika objek tersebut sudah ada dalam sesi ini, jangan lakukan apa pun
  • jika objek lain yang terkait dengan sesi tersebut memiliki pengenal yang sama, lemparkan pengecualian
  • jika objek tidak memiliki properti pengenal, simpan ()
  • jika pengenal objek memiliki nilai yang ditetapkan ke objek yang baru dibuat, simpan () itu
  • jika objek diversi (oleh <version> atau <timestamp>), dan nilai properti versi adalah nilai yang sama yang ditetapkan ke objek yang baru dibuat, simpan () itu
  • jika tidak perbarui () objek

dan merge () sangat berbeda:

  • jika ada instance persisten dengan pengenal yang sama yang saat ini terkait dengan sesi, salin status objek yang diberikan ke instance persisten
  • jika tidak ada instance persisten yang saat ini terkait dengan sesi, coba muat dari database, atau buat instance persisten baru
  • contoh persisten dikembalikan
  • contoh yang diberikan tidak menjadi terkait dengan sesi, itu tetap terlepas

Anda harus menggunakan Merge () jika Anda mencoba untuk memperbarui objek yang pada satu titik terlepas dari sesi, terutama jika mungkin ada contoh persisten dari objek yang saat ini terkait dengan sesi. Jika tidak, menggunakan SaveOrUpdate () dalam kasus itu akan menghasilkan pengecualian.

David Crow
sumber
jawaban yang bagus ... Saya ingin tahu - jika saya menggunakan merge pada entitas baru, apakah ada alasan untuk menggunakan save afterwords atau saya dapat berasumsi bahwa merge telah membuat entitas baru di DB dengan pasti? (dan jika itu adalah entitas yang terpisah, setelah penggabungan perubahan dihilangkan ke DB secara otomatis?)
Dani
5
Apa kau yakin tentang ini? Melihat sumber NHiberante SaveOrUpdateCopy memicu peristiwa Gabung dengan parameter yang sama seperti fungsi Gabung. Saya pikir mereka identik, fungsi SaveOrUpdateCopy adalah sesuatu yang telah ada di hibernate / nhibernate sejak 1.0 fungsi Gabung baru dan ditambahkan ke hibernasi agar sesuai dengan standar java baru (menurut saya)
Torkel
5
@Torkel - SaveOrUpdateCopytidak sama dengan SaveOrUpdate. Saya tidak yakin apakah penanya ingin membandingkan Mergeyang pertama atau yang terakhir. SaveOrUpdateCopyadalah metode yang sekarang sudah usang yang melakukan penggabungan di NHibernate sebelum Mergediimpor.
codekaizen
baik untuk diketahui ... SaveOrUpdate masih banyak digunakan dalam tutorial.
anael
9

Seperti yang saya pahami, merge()akan mengambil objek yang mungkin tidak terkait dengan sesi saat ini, dan copy negara (nilai properti, dll) untuk objek yang adalah terkait dengan sesi saat ini (dengan PK yang sama nilai / identifier, dari kursus).

saveOrUpdate()akan memanggil Simpan atau Perbarui pada sesi Anda, berdasarkan nilai identitas objek tertentu.

Ryan Duffield
sumber
4

SaveOrUpdateCopy()sekarang tidak digunakan lagi sejak NHibernate 3.1. Merge()harus digunakan sebagai gantinya.

Ricardo Peres
sumber
9
Itu SaveOrUpdateCopyyang ditandai Obsolete, bukan SaveOrUpdate. Tampaknya ada banyak kebingungan antara dua metode berbeda dalam pertanyaan ini dan jawaban berikutnya.
codekaizen
2
** Update()**

: - jika Anda yakin bahwa sesi tersebut tidak berisi instance yang sudah ada dengan pengenal yang sama, gunakan pembaruan untuk menyimpan data dalam mode hibernasi

** Merge()**

: -jika Anda ingin menyimpan modifikasi Anda setiap saat tanpa mengetahui tentang status sesi, gunakan merge () dalam hibernate.

Mohit Singh
sumber
1

Saya menemukan tautan ini yang cukup bagus menjelaskan jenis pengecualian ini:

Apa yang berhasil bagi saya adalah sebagai berikut:

  1. Dalam file pemetaan Myclass.hbm.xml, set cascade="merge"
  2. SaveOrUpdate objek anak / dependen terlebih dahulu sebelum menetapkannya ke objek induk.
  3. SaveOrUpdate objek induk.

Namun, solusi ini memiliki keterbatasan. yaitu, Anda harus berhati-hati dalam menyelamatkan anak Anda / objek dependen alih-alih membiarkan hibernasi melakukannya untuk Anda.

Jika ada yang punya solusi yang lebih baik, saya ingin melihat.

Quoc Truong
sumber
-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();
        }

    }
}
Deepak
sumber
2
Anda harus mempertimbangkan untuk mengedit jawaban Anda untuk menunjukkan kode yang terpengaruh dan kemudian mungkin mempertimbangkan dump kode lengkap di bagian akhir. Seperti berdiri kita harus menggulir ke bawah dan kesempatan di seluruh komentar. Lihat Bagaimana Menjawab .
Bugs