2008-10-04 10 views
82

Me doy cuenta a veces de mis objetos padre/hijo o relaciones de muchos a muchos, necesito llamar al SaveOrUpdate o al Merge. Por lo general, cuando necesito llamar al SaveOrUpdate, la excepción que recibo al llamar al Merge tiene que ver con objetos transitorios que no se guardan primero.¿Cuál es la diferencia entre session.Merge y session.SaveOrUpdate?

Por favor, explique la diferencia entre los dos.

Respuesta

152

Esto es de sección 10.7. Automatic state detection de la documentación de Hibernate Referencia:

saveOrUpdate() realiza lo siguiente:

  • si el objeto ya es persistente en esta sesión, no hacer nada
  • si otro objeto asociado con la sesión tiene el mismo identificador, arroja una excepción
  • si el objeto no tiene ident propiedad ifier, save() que
  • si el identificador del objeto tiene el valor asignado a un objeto recién instancia, salvar() que
  • si se versiona el objeto (por una versión < > o < marca de tiempo >), y el valor de la propiedad versión es el mismo valor asignado a un objeto recién instanciado , save() que
  • de otra manera actualizar() del objeto

y fusionar() es muy diferente:

  • si hay una instancia persistente con el mismo identificador Actualmente asociado con la sesión, copia el estado del objeto dado en la instancia persistente
  • si no hay ninguna instancia persistente actualmente asociado con la sesión , tratar de cargarlo desde la base de datos, o crear una nueva instancia persistente
  • se devuelve la instancia persistente
  • la instancia dada no asociado con la sesión, permanece distante

Debe utilizar Combinar() si usted está tratando de actualizar los objetos que estaban en un punto separado de la sesión, especialmente si puede haber casos persistentes de aquellos objetos que actualmente está asociada con la sesión. De lo contrario, usar SaveOrUpdate() en ese caso daría lugar a una excepción.

+2

Gracias. Esencialmente, estaba buscando esa documentación de referencia, ¡busqué en Google por un tiempo y no pude encontrarla! ¡Gracias! – EvilSyn

+0

buena respuesta ... Me pregunto: si utilizo fusionar en una entidad nueva ¿hay alguna razón para usar save afterwords o puedo suponer que merge ha creado la nueva entidad en la base de datos con seguridad? (¿Y si se trata de una entidad separada, una vez que se fusionan, los cambios se omiten automáticamente en el DB?) – Dani

+5

¿Estás seguro de esto? En cuanto a la fuente de NHiberante SaveOrUpdateCopy desencadena un evento Merge con los mismos parámetros que la función Merge. Creo que son idénticas, la función SaveOrUpdateCopy es algo que ha existido en hibernate/nhibernate desde 1.0 la función Merge es nueva y se agregó a hibernate para cumplir con un nuevo estándar de Java (creo) – Torkel

9

Como yo lo entiendo, merge() tendrá un objeto que no se puede asociar con la sesión actual, y copiar su estado (valores de la propiedad, etc.) a un objeto que es asociado con la sesión actual (con la mismo valor/identificador PK, por supuesto).

saveOrUpdate() llamarán Guardar o actualización en su reunión en base a valor de identidad de un objeto dado.

4

SaveOrUpdateCopy() ahora está en desuso a partir de NHibernate 3.1. Merge() se debe utilizar en su lugar.

+9

Es 'SaveOrUpdateCopy' que está marcado como' Obsoleto', no 'GuardarOrUpdate'. Parece que hay mucha confusión entre estos dos métodos diferentes en esta pregunta y las respuestas posteriores. – codekaizen

1

He encontrado this enlace que hizo un muy buen trabajo de explicar este tipo de excepción:

lo que funcionó para mí es la siguiente:

  1. En el archivo de asignación Myclass.hbm.xml, establecer cascade="merge"
  2. SaveOrUpdate el objeto secundario/dependiente primero antes de asignarlo al objeto primario.
  3. SaveOrUpdate el objeto primario.

Sin embargo, esta solución tiene limitaciones. es decir, debe cuidar de guardar su hijo/objeto dependiente en lugar de dejar que hibernate lo haga por usted.

Si alguien tiene una mejor solución, me gustaría verla.

1
** Update()** 

: - si está seguro de que la sesión no contiene una instancia ya persistente con el mismo identificador a continuación, utilizar la actualización para guardar los datos en hibernación

** Merge()** 

: - Si desea guardar sus modificaciones en cualquier momento sin conocer el estado de una sesión, utilice merge() en hibernación.

-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

Debería considerar editar su respuesta para mostrar el código que se está efectuando y luego considerar el volcado de código completo al final. Tal como está, tenemos que desplazarnos hacia abajo y al azar a través de los comentarios. Ver respuesta]. – Bugs

Cuestiones relacionadas