nhibernate - ¿Cuál es la diferencia entre session.Merge y session.SaveOrUpdate?
(7)
Encontré this enlace que hizo un buen trabajo al explicar este tipo de excepción:
Lo que funcionó para mí es lo siguiente:
- En el archivo de asignación Myclass.hbm.xml, establezca
cascade="merge"
-
SaveOrUpdate
el objeto secundario / dependiente primero antes de asignarlo al objeto principal. -
SaveOrUpdate
el objeto principal.
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.
A veces me doy cuenta de que con mis objetos padre / hijo o relaciones de muchos a muchos, necesito llamar SaveOrUpdate
o Merge
. Usualmente, cuando necesito llamar a SaveOrUpdate
, la excepción que obtengo al llamar a Merge
tiene que ver con que los objetos transitorios no se guarden primero.
Por favor explica la diferencia entre los dos.
Esto es de la sección 10.7. Detección automática de estado de la documentación de referencia de Hibernate:
saveOrUpdate () hace lo siguiente:
- si el objeto ya es persistente en esta sesión, no hagas nada
- si otro objeto asociado con la sesión tiene el mismo identificador, lanza una excepción
- si el objeto no tiene propiedad de identificador, guárdelo ()
- si el identificador del objeto tiene el valor asignado a un objeto recién instanciado, guárdelo ()
- si el objeto está versionado (por una <versión> o <timestamp>), y el valor de la propiedad de la versión es el mismo valor asignado a un objeto recién instanciado, guárdelo ()
- de lo contrario, actualice () el objeto
y merge () es muy diferente:
- si hay una instancia persistente con el mismo identificador actualmente asociado con la sesión, copie el estado del objeto dado en la instancia persistente
- si no hay una instancia persistente actualmente asociada con la sesión, intente cargarla desde la base de datos o cree una nueva instancia persistente
- la instancia persistente es devuelta
- la instancia dada no se asocia con la sesión, permanece separada
Debería usar Merge () si está tratando de actualizar objetos que estaban en un punto separado de la sesión, especialmente si puede haber instancias persistentes de esos objetos actualmente asociados con la sesión. De lo contrario, usar SaveOrUpdate () en ese caso daría lugar a una excepción.
Nueva identificación de usuario, así que no puedo comentar ni votar en la publicación de Quoc Truong. Sin embargo, también creo que el enlace es bastante útil como se dijo anteriormente.
Según lo entiendo, merge()
tomará un objeto que puede no estar asociado con la sesión actual, y copiará su estado (valores de propiedad, etc.) a un objeto que está asociado con la sesión actual (con el mismo valor de PK / identificador, por supuesto).
saveOrUpdate()
llamará a Guardar o Actualizar en su sesión, basado en el valor de identidad de un objeto dado.
SaveOrUpdateCopy()
ahora está en desuso a partir de NHibernate 3.1. Merge()
debería usarse en su lugar.
** Update()**
: - si está seguro de que la sesión no contiene una instancia ya persistente con el mismo identificador, utilice 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.
@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();
}
}
}