Win a copy of Programmer's Guide to Java SE 8 Oracle Certified Associate (OCA) this week in the OCAJP forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

disappearing collection items

 
Alan Shiers
Ranch Hand
Posts: 237
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 17278
6
IntelliJ IDE Mac Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
Alan Shiers
Ranch Hand
Posts: 237
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 17278
6
IntelliJ IDE Mac Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic