I was trying to write a simple testing program to simulate two objects in my project and run into trouble. Basically I have two simple object, Parent and Child with one to many relationship. Following are two objects:
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.fhp.ems.common.data.dao.HibernateInitializer;
@Entity
@Table(name = "Parent")
public class Parent {
private Integer id;
private String data;
private List<Child> child;
public Parent() {}
@Id
@Column(name = "ID", nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "DATA", length = 128)
public String getData() {
return this.data;
}
public void setData(String data) {
this.data = data;
}
@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinColumn(name = "PID")
//@Fetch(value=FetchMode.SELECT)
public List<Child> getChild() {
return child;
}
public void setChild(List<Child> child) {
this.child = child;
if(child != null && child.size() > 0) {
for(Child c : child) {
this.data = c.getValue();
}
}
}
public static void main(String[] args) {
Session session = null;
Transaction tx = null;
try {
HibernateInitializer.initLocal();
session = HibernateInitializer.getSession(null);
int id = 101;
tx = session.beginTransaction();
Parent p = (Parent)session.get(Parent.class, 101);
//Parent p = new Parent();
//p.setId(id);
//Child c = new Child();
//c.setPid(id);
//c.setId(1);
//c.setValue("child");
//Child c1 = new Child();
//c1.setPid(id);
//c1.setId(2);
//c1.setValue("child1");
//List<Child> childs = new ArrayList<Child>();
//childs.add(c);
//childs.add(c1);
//p.setChild(childs);
//session.saveOrUpdate(p);
tx.commit();
}
catch(Exception exc) {
exc.printStackTrace();
}
finally {
HibernateInitializer.closeSession(session, null);
}
}
}
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
//CREATE TABLE `Child` (
// `ID` int(11) NOT NULL,
// `PID` int(11) NOT NULL,
// `VALUE` varchar(128) default NULL,
// PRIMARY KEY (`ID`)
//)
@Entity
@Table(name = "Child")
public class Child {
private Integer id;
private Integer pid;
private String value;
public Child() {}
@Id
@Column(name = "ID", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "PID", nullable = false)
public Integer getPid() {
return this.pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
@Column(name = "VALUE", length = 128)
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
}
When I run the program, I get following error:
Hibernate:
select
parent0_.ID as ID81_1_,
parent0_.DATA as DATA81_1_,
child1_.PID as PID81_3_,
child1_.ID as ID3_,
child1_.ID as ID82_0_,
child1_.PID as PID82_0_,
child1_.VALUE as VALUE82_0_
from
Parent parent0_
left outer join
Child child1_
on parent0_.ID=child1_.PID
where
parent0_.ID=?
org.hibernate.PropertyAccessException: Exception occurred inside setter
of com.fhp.ems.common.data.dao.test.Parent.child
at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:89)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.setPropertyValues(AbstractEntityTuplizer.java:583)
at org.hibernate.tuple.entity.PojoEntityTuplizer.setPropertyValues(PojoEntityTuplizer.java:229)
at org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:3822)
at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:152)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:982)
at org.hibernate.loader.Loader.doQuery(Loader.java:857)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
at org.hibernate.loader.Loader.loadEntity(Loader.java:2037)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:86)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:76)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3268)
at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:496)
at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:477)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:227)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:285)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:152)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1090)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:1005)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:998)
at com.fhp.ems.common.data.dao.test.Parent.main(Parent.java:98)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:66)
... 20 more
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:122)
at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248)
at com.fhp.ems.common.data.dao.test.Parent.setChild(Parent.java:71)
If I change the earger fetch to lazy fetch, it works fine. If I use @Fetch(value=FetchMode.SELECT), it also works fine. My question is: why eager fetch does not work?
How can you have a
@OneToMany
when you don't haveParentId
in child table?You are missing a key to have a multiple children related to single parent; add
ParentId
to tableChild
and use that column in@JoinColumn(name = "ParentId")
EDIT:
Parent.child
withprivate List<Child> child = new ArrayList<Child>();
private Integer pid;
withprivate Parent pid;
(and add to @OneToMane mappedBy="parent")Parent.setChild()
just an assignmentThat are - usually - the best pratice for a parent-child relationship