There's something odd going on here if you get a NonUniqueObjectException when loading an entity that already exists in another entity's collection. I've built a simple test case to verify that hibernate returns the same java object through load() when that object has already been retrieved in a collection. Try and narrow down your problem and post the resultant mappings and java files.
My test (using annotations):
Child.java
Code:
package test.collection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames={"uniqueName"})})
public class Child {
private Long id;
private String uniqueName;
private Parent parent;
@ManyToOne
@JoinColumn(name="parent_fk", insertable=false, updatable=false)
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
@Id @GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUniqueName() {
return uniqueName;
}
public void setUniqueName(String uniqueName) {
this.uniqueName = uniqueName;
}
}
Parent.java
Code:
package test.collection;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
@Entity
public class Parent {
private Long id1;
private List<Child> children;
@Id @GeneratedValue(strategy=GenerationType.AUTO)
public Long getId1() {
return id1;
}
public void setId1(Long id) {
this.id1 = id;
}
@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="parent_fk")
public List<Child> getChildren() {
return children;
}
public void setChildren(List<Child> children) {
this.children = children;
}
}
TestIt.java
Code:
package test.collection;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.hibernate.Session;
public class TestIt extends TestCase {
public void testIt() {
createTestObjects();
Session session = HibernateUtil.getSession();
// Load the parent object.
Parent p = (Parent)session.createCriteria(Parent.class).uniqueResult();
// Get a child reference from the collection in parent.
Child child = p.getChildren().get(0);
// Load the same child with session.load().
Child sameChild = (Child)session.load(Child.class, child.getId());
// Hibernate should return the same instance of the child object.
assertTrue(child == sameChild);
session.close();
}
private void createTestObjects() {
Session session = HibernateUtil.getSession();
session.beginTransaction();
List<Child> children = new ArrayList<Child>();
Child c1 = new Child();
c1.setUniqueName("c1");
children.add(c1);
Child c2 = new Child();
c2.setUniqueName("c2");
children.add(c2);
Parent parent = new Parent();
parent.setChildren(children);
session.save(parent);
session.getTransaction().commit();
session.close();
}
}
HibernateUtil.java
Code:
package test.collectionbug;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static SessionFactory factory;
static {
Configuration config = new AnnotationConfiguration()
.addAnnotatedClass(Parent.class)
.addAnnotatedClass(Child.class)
// HSQLDB configuration
.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect")
.setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver")
.setProperty("hibernate.connection.url", "jdbc:hsqldb:mem:test")
.setProperty("hibernate.connection.username", "sa")
.setProperty("hibernate.connection.password", "")
.setProperty("hibernate.hbm2ddl.auto", "create-drop")
// MYSQL configuration
// .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect")
// .setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver")
// .setProperty("hibernate.connection.url", "jdbc:mysql://localhost/test")
// .setProperty("hibernate.connection.username", "root")
// .setProperty("hibernate.connection.password", "password")
// .setProperty("hibernate.hbm2ddl.auto", "create-drop")
// Common properties
.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider")
.setProperty("hibernate.show_sql", "true");
HibernateUtil.setSessionFactory(config.buildSessionFactory());
}
public static synchronized Session getSession() {
if (factory == null) {
factory = new Configuration().configure().buildSessionFactory();
}
return factory.openSession();
}
public static void setSessionFactory(SessionFactory factory) {
HibernateUtil.factory = factory;
}
}