views:

513

answers:

3

Okay, I've used Hibernate in several projects now but I did not learn its intricacies before using it. I started with looking at codes that used JPA Annotations and integrated with Spring and everything worked well. But now that I want to teach basic Hibernate to my students and I'm in the process of creating an example and using the documentation tutorial Chapter 1, I'm having a problem with saving a Set of collection values in one persistent class.

Here's the persistent class...

public class Student {
    private Long id;
    private String firstName;
    private String lastName;
    private Set<Course> courses = new HashSet<Course>();
    private Set<String> contactDetails = new HashSet<String>();

    //getters and setters
}

The mapping file...

<hibernate-mapping package="com.phoenixone.school.model">
    <class name="Student" table="student">
     <id name="id" column="studentId">
     <generator class="native" />
     </id>

     <property name="firstName" />
     <property name="lastName" />

     <set name="courses" table="student_course" lazy="false">
      <key column="studentId" />
     <many-to-many column="courseId" class="Course" />
     </set>

     <set name="contactDetails" table="contactDetails">
      <key column="studentId" />
      <element type="string" column="contactDetail" />
     </set>
    </class>
</hibernate-mapping>

The DAO (saving part)

public class StudentDaoHibernate {
    public void save(Student student){
     Session session = HibernateUtil.getSessionFactory().getCurrentSession();
     session.beginTransaction();

     session.save(student);
     session.getTransaction().commit();
    }
}

The testing part...

public class TestStudentDaoHibernate {
    public static void main(String[] args) {
     CourseDaoHibernate courseDao = new CourseDaoHibernate();

     Course c1 = new Course();
     c1.setCourseCode("CWD");
     c1.setCourseName("Web Dev");
     courseDao.save(c1);

     Set<Course> courses = new HashSet<Course>();
     courses.add(c1);

     Student student = new Student();
     student.setFirstName("Bob");
     student.setLastName("Santos");
     student.setCourses(courses);
     student.getContactDetails().add("123456789");                 

                StudentDaoHibernate dao = new StudentDaoHibernate();
     dao.save(student);
    }
}

When I execute these lines of code...

Session session = HibernateUtil.getSessionFactory().getCurrentSession()
session.beginTransaction();
Student student = (Student)session.createCriteria(Student.class)
          .add(Restrictions.eq("id", new Long(1))).uniqueResult();
System.out.println("First Name: " + student.getFirstName());
System.out.println("Last Name: " + student.getLastName());

System.out.println("Courses enrolled with...");
for(Course c:student.getCourses()){
    System.out.println(c.getCourseName());
}

System.out.println("Contact details...");
for(String s:student.getContactDetails()){
    System.out.println(s);
}

What I get is this...

First Name: Bob
Last Name: Santos
Courses enrolled with...
Web Dev
Contact details...

Which leads me to the conclusion that the String "123456789" was not saved. What do you think is the problem with my code? Thanks!

A: 

I'd recommend creating a Contract class and using that instead of a String. It's a better abstraction, and the evidence that Hibernate dealt with your Course class just fine suggests that it'll work well with Contract, too.

duffymo
Thanks duffymo for the suggestion. I would have made a Contact class as well if not for following the tutorial.:|Do you have any idea why it did not persist?
bob_santos
Not right now, but perhaps I'll try it on my own tonight and get back to you.
duffymo
Do come back duffy. Thanks!
bob_santos
+1  A: 

You need to add a cascade attribute to your set elements for courses and contactDetails. This defines what operations performed on the parent entity will be applied to the child entity. The default value is none which is why when you saved the Student none of the child elements in the sets where saved.

Adding cascade="all,delete-orphan" will cover all operations but you can be more restrictive if you wish. See here in the Hibernate reference for more details.

Mark
Hi Mark! I had no problem in saving the Set<Course> only with the Set<String> which I think because it's a collection of values not a collection of entities. I've added cascade="all" to both <set> elements in the mapping file as you've suggested. Unfortunately I still had the same result.
bob_santos
A: 

Any other answers please? Thanks in advance!

bob_santos