Isso é da seção 10.7. Detecção automática de estado da documentação de referência do Hibernate:
saveOrUpdate () faz o seguinte:
- se o objeto já é persistente nesta sessão, não faça nada
- se outro objeto associado à sessão tiver o mesmo identificador, lance uma exceção
- se o objeto não tem propriedade identificadora, save () it
- se o identificador do objeto tiver o valor atribuído a um objeto recém-instanciado, salve ()
- se o objeto for versionado (por uma <version> ou <timestamp>), e o valor da propriedade da versão for o mesmo valor atribuído a um objeto recém-instanciado, salve ()
- caso contrário, update () o objeto
e merge () é muito diferente:
- se houver uma instância persistente com o mesmo identificador atualmente associado à sessão, copie o estado do objeto fornecido para a instância persistente
- se não houver uma instância persistente atualmente associada à sessão, tente carregá-la do banco de dados ou crie uma nova instância persistente
- a instância persistente é retornada
- a instância dada não se torna associada à sessão, ela permanece separada
Você deve usar Merge () se estiver tentando atualizar objetos que em um ponto foram desconectados da sessão, especialmente se houver instâncias persistentes desses objetos atualmente associados à sessão. Caso contrário, usar SaveOrUpdate () nesse caso resultaria em uma exceção.
SaveOrUpdateCopy
não é o mesmo queSaveOrUpdate
. Não tenho certeza se o questionador queria compararMerge
o primeiro ou o último.SaveOrUpdateCopy
é um método obsoleto que fez uma fusão no NHibernate antes deMerge
ser importado.Pelo que entendi,
merge()
pegarei um objeto que não pode estar associado à sessão atual e copiará seu estado (valores de propriedade, etc.) para um objeto que está associado à sessão atual (com o mesmo valor / identificador de PK, de curso).saveOrUpdate()
irá chamar Salvar ou Atualizar em sua sessão, com base no valor de identidade de um determinado objeto.fonte
SaveOrUpdateCopy()
agora está obsoleto a partir do NHibernate 3.1.Merge()
deve ser usado em seu lugar.fonte
SaveOrUpdateCopy
que está marcadoObsolete
, nãoSaveOrUpdate
. Parece haver muita confusão entre esses dois métodos diferentes nesta pergunta e nas respostas subsequentes.** Update()**
: - se você tiver certeza de que a sessão não contém uma instância já persistente com o mesmo identificador, use update para salvar os dados no hibernar
** Merge()**
: -se você deseja salvar suas modificações a qualquer momento sem saber sobre o estado de uma sessão, então use merge () para hibernar.
fonte
Encontrei este link que explicou muito bem esse tipo de exceção:
O que funcionou para mim é o seguinte:
cascade="merge"
SaveOrUpdate
o objeto filho / dependente antes de atribuí-lo ao objeto pai.SaveOrUpdate
o objeto pai.No entanto, esta solução tem limitações. ou seja, você deve cuidar para salvar seu filho / objeto dependente em vez de deixar que o hibernate faça isso por você.
Se alguém tiver uma solução melhor, eu gostaria de ver.
fonte
@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(); } } }
fonte