Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp
Hello,
I'm trying to save a new object (which doesn't exist in database already) in the database using session.merge(). Though it works fine when session.merge() is called only once, it throws exception when session.merge(obj) is called second time. Note that this is not an issue if the object is loaded from the database (i.e., we can call session.merge(obj) multiple times if the object is loaded from database)
Note that as per requirements we want to use the same session through out application life time (so, closing and opening the session is ruled out) and we don't want to use (session.saveOrUpdate(obj)).
Please let me know if I'm not clear or I need to provide any other information.
thanks
Ranadheer
Hibernate version: 3.2.6
Mapping documents:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.sybase.jdbc3.jdbc.SybDriver</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.SybaseDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<mapping class="hello.Person"/>
<mapping class="hello.PersonInfo"/>
</session-factory>
</hibernate-configuration>
Code between sessionFactory.openSession() and session.close():
Full stack trace of any exception that occurs:
Exception in thread "main" org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [hello.PersonInfo#ppp]
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:168)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:186)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:123)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:687)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:669)
at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:245)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:407)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:266)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:120)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:53)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:661)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:665)
at hello.HelloPerson.save(HelloPerson.java:31)
at hello.HelloPerson.main(HelloPerson.java:52)
Name and version of the database you are using: Sybase & Adavptive Server Enterprice 15.0
The generated SQL (show_sql=true):
Hibernate: select this_.name as name0_1_, personinfo2_.name as name1_0_ from person this_ left outer join person_info personinfo2_ on this_.name=personinfo2_.name where this_.name=?
Hibernate: select person0_.name as name0_1_, personinfo1_.name as name1_0_ from person person0_ left outer join person_info personinfo1_ on person0_.name=personinfo1_.name where person0_.name=?
Hibernate: insert into person (name) values (?)
Hibernate: insert into person_info (name) values (?)
Debug level Hibernate log excerpt:
Hibernate: select this_.name as name0_1_, personinfo2_.name as name1_0_ from person this_ left outer join person_info personinfo2_ on this_.name=personinfo2_.name where this_.name=?
Hibernate: select person0_.name as name0_1_, personinfo1_.name as name1_0_ from person person0_ left outer join person_info personinfo1_ on person0_.name=personinfo1_.name where person0_.name=?
Hibernate: insert into person (name) values (?)
Hibernate: insert into person_info (name) values (?)
Exception in thread "main" org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [hello.PersonInfo#ppp]
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:168)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:186)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:123)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:687)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:669)
at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:245)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:407)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:266)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:120)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:53)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:661)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:665)
at hello.HelloPerson.save(HelloPerson.java:31)
at hello.HelloPerson.main(HelloPerson.java:52)
Problems with Session and transaction handling?
Read this:
http://hibernate.org/42.html
Code:
/** HibernateUtil.java **/
package util;
import org.hibernate.*;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.criterion.Criterion;
public class HibernateUtil {
private static final SessionFactory ourSessionFactory;
private static Session ourSession;
static {
try {
ourSessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
ourSession = HibernateUtil.getSessionFactory().openSession();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return ourSessionFactory;
}
public static Session getSession() {
if (!ourSession.isOpen()) {
ourSession = ourSessionFactory.openSession();
}
return ourSession;
}
public static<T> T findUniqueByCriteria(Class<?> persistentClass,
Criterion... criterion)
{
Criteria criteria =
getSession().createCriteria(persistentClass);
for (Criterion c : criterion) {
criteria.add(c);
}
return (T) criteria.uniqueResult();
}
}
Code:
/** Person.java **/
package hello;
import javax.persistence.*;
import javax.persistence.Table;
@Entity
@Table(name = "person")
public class Person
{
private String myName;
private PersonInfo myPersonInfo;
public Person() {}
public Person(String name)
{
myName = name;
}
@Id
@Column(name = "name")
public String getName()
{
return myName;
}
public void setName(String name)
{
myName = name;
}
@OneToOne(cascade = CascadeType.ALL, optional = true)
@PrimaryKeyJoinColumn
public PersonInfo getPersonInfo()
{
return myPersonInfo;
}
public void setPersonInfo(PersonInfo personInfo)
{
myPersonInfo = personInfo;
}
}
Code:
/** PersonInfo **/
package hello;
import javax.persistence.*;
import org.hibernate.annotations.Parameter;
@Entity
@Table(name="person_info")
@Inheritance(strategy=InheritanceType.JOINED)
public class PersonInfo
{
private String myPersonId;
private Person myPerson;
@Id @GeneratedValue(generator = "myForeignGenerator")
@org.hibernate.annotations.GenericGenerator(
name = "myForeignGenerator",
strategy = "foreign",
parameters = @Parameter(name = "property", value = "person"))
@Column (name = "name")
public String getPersonId()
{
return myPersonId;
}
public void setPersonId(String personId)
{
this.myPersonId = personId;
}
@OneToOne(cascade = CascadeType.ALL, optional = false)
@PrimaryKeyJoinColumn
public Person getPerson()
{
return myPerson;
}
public void setPerson(Person person)
{
myPerson = person;
}
}
Code:
package hello;
import util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Expression;
public class HelloPerson
{
private static Person save(Person person)
{
Transaction tx = null;
Session sess = HibernateUtil.getSession();
tx = sess.beginTransaction();
sess.merge(person);
tx.commit();
return person;
}
public static void main(String[] args)
{
String name = "ravi";
Criterion criterion = Expression.eq("name", name);
Person person =
HibernateUtil.findUniqueByCriteria(Person.class, criterion);
if (person == null) {
person = new Person(name);
PersonInfo personInfo = new PersonInfo();
person.setPersonInfo(personInfo);
personInfo.setPerson(person);
}
save(person);
save(person);
}
}