This week's book giveaway is in the Servlets forum.
We're giving away four copies of Murach's Java Servlets and JSP and have Joel Murach on-line!
See this thread for details.
The moose likes Object Relational Mapping and the fly likes disappearing collection items Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Databases » Object Relational Mapping
Bookmark "disappearing collection items" Watch "disappearing collection items" New topic
Author

disappearing collection items

Alan Shiers
Ranch Hand

Joined: Sep 24, 2003
Posts: 237
Hi there,

Could someone please explain what's going on here. I have a class named ScheduledCourse. It contains a collection of type Enroll. The Student class is the same. The Enroll class is an entity class (creates the ENROLL table) that serves as an intermediate join table between tables SCHEDULED_COURSES and STUDENTS. When I enroll a student I simply create an instance of type Enroll. Its constructor automatically adds the instance to the collections in instances of ScheduledCourse and Student. When I run my test code for the first unit of work I load the collections. The println statements reveal the proper amounts. The instance of ScheduledCourse has three Enroll instances, while each of the Student instances have one.

So far, so good.

But wait, what's happening in the 2nd. unit of work? I use:
sc2 = em2.find(ScheduledCourse.class, index);
to bring the instance of ScheduledCourse back into the persistant context and use a println statement to have a look at the size of the collection of type Enroll. It's zero! This isn't good! Why is it zero? What happened to my instances of Enroll?

See test code below:

//First unit of work
EntityManager em1 = emf.createEntityManager();
EntityTransaction tx1 = em1.getTransaction();
tx1.begin();

//Create a ScheduledCourse
ScheduledCourse sc1 = new ScheduledCourse(...);
em1.persist(sc1);
Long index = sc1.getId();
//Enroll several students into the course
//ScheduledCourse has a collection of type Enroll
//The following automatically adds these to the collections
//in ScheduledCourse and Student
Enroll enroll1 = new Enroll(company, admin1, student1, scheduled_course);
em1.persist(enroll1);
Enroll enroll2 = new Enroll(company, admin1, student2, scheduled_course);
em1.persist(enroll2);
Enroll enroll3 = new Enroll(company, admin1, student3, scheduled_course);
em1.persist(enroll3);

System.out.println("Adding students to the collections in scheduled course and students...");
System.out.println("scheduled_course.getEnrolled().size(): " + scheduled_course.getEnrolled().size()); //reveals 3
System.out.println("enroll1.getStudent().getEnrolled().size(): " + enroll1.getStudent().getEnrolled().size());//reveals 1
System.out.println("enroll2.getStudent().getEnrolled().size(): " + enroll2.getStudent().getEnrolled().size());//reveals 1
System.out.println("enroll3.getStudent().getEnrolled().size(): " + enroll3.getStudent().getEnrolled().size());//reveals 1

tx1.commit();
em1.close();

//Perform 2nd Unit of work
EntityManager em2 = emf.createEntityManager();
EntityTransaction tx2 = em2.getTransaction();
tx2.begin();

ScheduledCourse sc2 = em2.find(ScheduledCourse.class, index);

System.out.println("Enroll collection size: " + sc2.getEnrolled().size()); //reveals 0 Zero

tx2.commit();
em2.close();

The following code reveals that the records got recorded in the ENROLL table:

List enrolled = em2.createQuery("select e from Enroll e").getResultList();
System.out.println(enrolled.size() + " students enrolled"); //reveals 3

That's fine, but the collection is showing zero. Did something happen to the collection when the instance of ScheduledCourse became detached from the persistent context? I don't get it...

Please advise,

Alan

[ February 17, 2007: Message edited by: Alan Shiers ]
[ February 17, 2007: Message edited by: Alan Shiers ]
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17249
    
    6

Look like it is lazy loading the Collection, meaning your call to size() is calling an unitialized Collection. You can try to eager load them, or instead of calling size() loop through the collection printing them out one by one.

Also, what is most important to tell us what is going on is seeing your mapping files.

Mark


Perfect World Programming, LLC - Two Laptop Bag - Tube Organizer
How to Ask Questions the Smart Way FAQ
Alan Shiers
Ranch Hand

Joined: Sep 24, 2003
Posts: 237
I had to look up this business of lazy and eager loading.
I wound up adding the following (fetch = FetchType.EAGER) to my annotations:

@OneToMany(fetch = FetchType.EAGER, mappedBy="scheduled_course")
@org.hibernate.annotations.CollectionOfElements
@JoinTable(name = "ENROLL", joinColumns = @JoinColumn(name = "ENROLL_ID"))
private Collection<Enroll> ENROLLED = new ArrayList<Enroll>();

in ScheduledCourse.

However, it seems to be ineffectual when I ran my test app:

System.out.println("\nStarting second unit of work.");
//Start EnityManagerFactory
EntityManager em2 = emf.createEntityManager();
EntityTransaction tx2 = em2.getTransaction();
tx2.begin();

scheduled_course = em2.find(ScheduledCourse.class, index);

Collection<Enroll> c = scheduled_course.getEnrolled();
Iterator<Enroll> itr = c.iterator();
while(itr.hasNext())
{
Enroll en = itr.next();
Student st = en.getStudent();
System.out.println("student: " + st.getFullName());
}
tx2.commit();
em2.close();

Inside the persistence context the collection still had nothing in it as the println statement was never executed.
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17249
    
    6

OK, so we are missing some things.

First We should rewrite the following code in session #1



to



Now the constructor in the Enroll class has to set both sides. Not just adding the Enroll into the scheduled_course object's Collection, but also setting the scheduled_course's reference in the Enroll object.

What is you mapping for Enroll?

Anyway, also add/change the following to your Mapping


Since the table name is "ENROLL" the same as the Class name, and the PK is "ENROLL_ID" you do not need the @JoinColumn and @JoinTable, you can use the defaults, which is "ENROLL" and "ENROLL_ID"


Mark
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: disappearing collection items
 
Similar Threads
understanding persistence
Could not synchronize
unwanted cascade delete behaviour
Object and reference accessing for primitives, objecst and collections
Entity in two persistence units