NHibernate – session.Merge和session.SaveOrUpdate之间的区别?
我有时会注意到我的父/子对象或多对多关系,我需要调用SaveOrUpdate或Merge。 通常情况下,当我需要调用SaveOrUpdate时,调用Merge时遇到的exception与暂时不保存的对象有关。请解释两者之间的区别。
这是从第10.7节。 自动状态检测 Hibernate参考文档:
saveOrUpdate()执行以下操作:
- 如果该对象已经在这个会话中持久化,则什么也不做
- 如果与会话关联的另一个对象具有相同的标识符,则抛出exception
- 如果对象没有标识符属性,则保存()它
- 如果对象的标识符具有赋值给新实例化对象的值,则save()
- 如果对象是版本化的(由<版本>或<时间戳>),并且版本属性值是分配给新实例化对象的相同值,则save()
- 否则更新()该对象
和merge()是非常不同的:
- 如果存在与会话相关的当前标识符的持久实例,则将给定对象的状态复制到持久实例上
- 如果当前没有与会话关联的持久实例,请尝试从数据库加载它,或者创build一个新的持久实例
- 持久实例被返回
- 给定的实例不会与会话关联,它仍然是分离的
如果您尝试更新与会话分离的某个点的对象,则应该使用Merge(),特别是当可能存在与会话当前关联的对象的持久实例时。 否则,在这种情况下使用SaveOrUpdate()会导致exception。
据我所知, merge()
会把一个可能不会与当前会话关联的对象,并将其状态(属性值等)复制到与当前会话相关联的对象(具有相同的PK值/标识符,当然)。
saveOrUpdate()
将根据给定对象的标识值调用会话上的保存或更新 。
SaveOrUpdateCopy()
从NHibernate 3.1开始已经被弃用了。 应该使用Merge()
。
我发现这个链接做了很好的解释这种types的exception:
对我有用的是以下几点:
- 在映射Myclass.hbm.xml文件中,设置
cascade="merge"
- 在将其分配给父对象之前,先
SaveOrUpdate
或更新子对象/从属对象。 -
SaveOrUpdate
父对象。
但是,这个解决scheme有局限性。 即,你必须照顾保存你的孩子/依赖对象,而不是让hibernate为你做这件事。
如果有人有更好的解决办法,我想看看。
新的用户名,所以我不能评论或投票在Quoc Truong的post。 但是,我也认为这个链接如前所述是相当有帮助的。
http://www.roseindia.net/hibernate/hibernate4/org_hibernate_nonuniqueobjectexception.shtml
** Update()**
: – 如果您确定会话中不包含具有相同标识符的已经存在的实例,则使用update来将数据保存在hibernate中
** Merge()**
: – 如果您想随时了解会话的状态,随时保存您的修改,然后在hibernate中使用merge()。
@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(); } } }