Was ist der Unterschied zwischen session.Merge und session.SaveOrUpdate?

86

Ich stelle manchmal fest, dass ich mit meinen Eltern / Kind-Objekten oder vielen-zu-vielen-Beziehungen entweder SaveOrUpdateoder aufrufen muss Merge. Wenn ich anrufen muss SaveOrUpdate, hat die Ausnahme, die ich beim Anrufen erhalte Merge, normalerweise damit zu tun, dass vorübergehende Objekte nicht zuerst gespeichert werden.

Bitte erläutern Sie den Unterschied zwischen den beiden.

EvilSyn
quelle

Antworten:

157

Dies ist aus Abschnitt 10.7. Automatische Statuserkennung der Referenzdokumentation für den Ruhezustand:

saveOrUpdate () führt Folgendes aus:

  • Wenn das Objekt in dieser Sitzung bereits persistent ist, führen Sie nichts aus
  • Wenn ein anderes der Sitzung zugeordnetes Objekt dieselbe Kennung hat, wird eine Ausnahme ausgelöst
  • Wenn das Objekt keine Bezeichner-Eigenschaft hat, speichern Sie es ()
  • Wenn der Bezeichner des Objekts den Wert hat, der einem neu instanziierten Objekt zugewiesen wurde, speichern Sie ihn ()
  • Wenn das Objekt versioniert ist (durch eine <Version> oder einen <Zeitstempel>) und der Versionseigenschaftswert der gleiche Wert ist, der einem neu instanziierten Objekt zugewiesen wurde, speichern Sie ihn ()
  • Andernfalls aktualisieren () Sie das Objekt

und merge () ist sehr unterschiedlich:

  • Wenn der Sitzung eine persistente Instanz mit demselben Bezeichner zugeordnet ist, kopieren Sie den Status des angegebenen Objekts auf die persistente Instanz
  • Wenn der Sitzung derzeit keine persistente Instanz zugeordnet ist, versuchen Sie, sie aus der Datenbank zu laden, oder erstellen Sie eine neue persistente Instanz
  • Die persistente Instanz wird zurückgegeben
  • Die angegebene Instanz wird nicht mit der Sitzung verknüpft, sondern bleibt getrennt

Sie sollten Merge () verwenden, wenn Sie versuchen, Objekte zu aktualisieren, die zu einem bestimmten Zeitpunkt von der Sitzung getrennt waren, insbesondere wenn möglicherweise dauerhafte Instanzen dieser Objekte vorhanden sind, die derzeit der Sitzung zugeordnet sind. Andernfalls würde die Verwendung von SaveOrUpdate () in diesem Fall zu einer Ausnahme führen.

David Crow
quelle
Gute Antwort ... Ich frage mich: Wenn ich für eine neue Entität die Zusammenführung verwende, gibt es einen Grund für die Verwendung von Nachwörtern zum Speichern, oder ich kann davon ausgehen, dass die Zusammenführung die neue Entität in der Datenbank sicher erstellt hat. (und wenn es sich um eine getrennte Entität handelt, werden die Änderungen nach dem Zusammenführen automatisch in der Datenbank weggelassen?)
Dani
5
Bist du dir da sicher? Wenn Sie sich die NHiberante-Quelle ansehen, löst SaveOrUpdateCopy ein Merge-Ereignis mit denselben Parametern wie die Merge-Funktion aus. Ich denke, dass sie identisch sind, die SaveOrUpdateCopy-Funktion ist etwas, das seit 1.0 im Ruhezustand / Ruhezustand existiert. Die Merge-Funktion ist neu und wurde zum Ruhezustand hinzugefügt, um einem neuen Java-Standard zu entsprechen (glaube ich)
Torkel
5
@Torkel - SaveOrUpdateCopyist nicht dasselbe wie SaveOrUpdate. Ich bin mir nicht sicher, ob der Fragesteller Mergedas erstere oder das letztere vergleichen wollte . SaveOrUpdateCopyist eine veraltete Methode, die vor Mergedem Import in NHibernate zusammengeführt wurde .
Codekaizen
Gut zu wissen ... SaveOrUpdate wird in Tutorials immer noch häufig verwendet.
Anael
9

Wie ich es verstehe, merge()wird ein Objekt nehmen, die ein Objekt kann nicht mit der aktuellen Sitzung in Verbindung gebracht werden, und kopieren Sie die Zustand (Eigenschaftswert, etc.) , die sich mit der aktuellen Sitzung zugeordnet ist (mit der gleichen PK Wert / Kennung, von Kurs).

saveOrUpdate() werde anrufen in Ihrer Sitzung Speichern oder Aktualisieren auf, basierend auf dem Identitätswert eines bestimmten Objekts.

Ryan Duffield
quelle
4

SaveOrUpdateCopy()ist ab NHibernate 3.1 veraltet. Merge()sollte stattdessen verwendet werden.

Ricardo Peres
quelle
9
Es ist das, SaveOrUpdateCopywas markiert ist Obsolete, nicht SaveOrUpdate. Es scheint viel Verwirrung zwischen diesen beiden unterschiedlichen Methoden in dieser Frage und den nachfolgenden Antworten zu geben.
Codekaizen
2
** Update()**

: - Wenn Sie sicher sind, dass die Sitzung keine bereits persistente Instanz mit derselben Kennung enthält, verwenden Sie update, um die Daten im Ruhezustand zu speichern

** Merge()**

: -wenn Sie Ihre Änderungen jederzeit speichern möchten, ohne den Status einer Sitzung zu kennen, verwenden Sie merge () im Ruhezustand.

Mohit Singh
quelle
1

Ich habe diesen Link gefunden , der diese Art von Ausnahme ziemlich gut erklärt hat:

Was für mich funktioniert hat, ist Folgendes:

  1. Legen Sie in der Zuordnungsdatei Myclass.hbm.xml fest cascade="merge"
  2. SaveOrUpdate Das untergeordnete / abhängige Objekt zuerst, bevor es dem übergeordneten Objekt zugewiesen wird.
  3. SaveOrUpdate das übergeordnete Objekt.

Diese Lösung weist jedoch Einschränkungen auf. Das heißt, Sie müssen darauf achten, Ihr Kind / abhängiges Objekt zu retten, anstatt den Ruhezustand dies für Sie tun zu lassen.

Wenn jemand eine bessere Lösung hat, würde ich gerne sehen.

Quoc Truong
quelle
-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
quelle
2
Sie sollten in Betracht ziehen, Ihre Antwort zu bearbeiten, um den betroffenen Code anzuzeigen, und dann möglicherweise den vollständigen Code-Dump am Ende in Betracht ziehen. So wie es aussieht, müssen wir nach unten scrollen und über die Kommentare streichen. Siehe Antworten .
Fehler