Какая разница между session.Merge и session.SaveOrUpdate?
Я иногда замечаю свои родительские/дочерние объекты или отношения "многие ко многим", мне нужно позвонить либо SaveOrUpdate
, либо Merge
. Обычно, когда мне нужно вызывать SaveOrUpdate
, исключение, которое я получаю при вызове Merge
, связано с тем, что ранее не сохраняются неработающие объекты.
Пожалуйста, объясните разницу между ними.
Ответы
Ответ 1
Это из раздела 10.7. Автоматическое определение состояния справочной документации Hibernate:
saveOrUpdate() выполняет следующие действия:
- Если объект уже настойчив в этом сеансе, ничего не делайте
- если другой объект, связанный с сеансом, имеет тот же идентификатор, исключить исключение
- если объект не имеет свойства идентификатора, save() it
- если идентификатор объекта имеет значение, присвоенное новому экземпляр объекта, save() it
- если объект имеет версию (посредством <version> или <timestamp> ), и значение свойства версии - это то же значение, что и новое экземпляр объекта, save() it
- иначе обновить() объект
и merge() очень разные:
- если в настоящее время существует постоянный экземпляр с тем же идентификатором связанные с сеансом, скопировать состояние данного объекта на постоянный экземпляр
- если нет постоянного экземпляра, связанного в настоящее время с сеанс, попробуйте загрузить его из базы данных или создать новую постоянную Экземпляр
- возвращается постоянный экземпляр
- данный экземпляр не ассоциируется с сеансом, он остается отсоединенным
Вы должны использовать Merge(), если вы пытаетесь обновить объекты, которые были в какой-то момент отделены от сеанса, особенно если могут быть постоянные экземпляры тех объектов, которые в настоящее время связаны с сеансом. В противном случае использование SaveOrUpdate() в этом случае приведет к исключению.
Ответ 2
Как я понимаю, merge()
возьмет объект, который не может быть связан с текущим сеансом, и скопируйте его состояние (значения свойств и т.д.) на объект, связанный с текущим сеансом (с тем же PK value/identifier, конечно).
saveOrUpdate()
будет вызывать Сохранить или Обновить в вашем сеансе на основе заданного значения идентификатора объекта.
Ответ 3
SaveOrUpdateCopy()
теперь устарел с NHibernate 3.1. Merge()
следует использовать вместо этого.
Ответ 4
Я нашел эту ссылку, которая неплохо справилась с объяснением этого типа исключения:
Что сработало для меня, это следующее:
- В файле Myclass.hbm.xml сопоставления установите
cascade="merge"
-
SaveOrUpdate
дочерний/зависимый объект перед назначением родительского объекта.
-
SaveOrUpdate
родительский объект.
Однако это решение имеет ограничения. то есть вы должны позаботиться о сохранении вашего дочернего/зависимого объекта вместо того, чтобы позволить hibernate делать это для вас.
Если у кого-то есть лучшее решение, я бы хотел увидеть.
Ответ 5
Новый идентификатор пользователя, поэтому я не могу комментировать или голосовать на пост Quoc Truong. Однако я также считаю, что ссылка очень полезна, как было сказано ранее.
http://www.roseindia.net/hibernate/hibernate4/org_hibernate_nonuniqueobjectexception.shtml
Ответ 6
** Update()**
: - если вы уверены, что сеанс не содержит уже сохраняющийся экземпляр с тем же идентификатором, используйте обновление для сохранения данных в спящем режиме
** Merge()**
: - если вы хотите сохранить свои изменения в любое время, не зная о состоянии сеанса, используйте слияние() в спящем режиме.
Ответ 7
@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();
}
}
}