I have a dilemma I'm trying to solve. I'll start by descibing a part of my small application. I have a hierarchy of classes like so:
abstract User | |__ Administrator extends User |__ Instructor extends User |__ Student extends User
In addition, I have a class named ScheduledCourse. It looks like so with a collection of instructors:
As you can see, there is an interim Table being created here that contains pointers to both the ScheduledCourse and the instructor. This is named: SCHEDULED_INSTRUCTORS. I'm not even sure the relationship should be OneToMany or ManyToMany. The logic is this: A ScheduledCourse can have more than one instructor teaching the course. By the same token, an instructor can teach more than one ScheduledCourse. Therefore, the instructor class also has a collection of type ScheduledCourse. So, what is this really? OneToMany or ManyToMany? I'm inclined to think it's the latter, isn't it? The instructor class is the opposite end of this relationship with a collection of ScheduledCourses:
What I want to do is test the EntityManager.remove(Object o) method and its cascading affect on an instance of ScheduledCourse. Assume the collection of instructors in ScheduledCourse has only one instructor in it. This is my test code:
When hibernate starts the deletions it certainly clears the SCHEDULED_INSTRUCTORS table, which is what I want, but it doesn't stop there! This is not good. It actually continues a cascade deletion of the instructor from the INSTRUCTORS table and USERS table. I don't want it to do that! Could someone please explain what it is I need to do to get the appropriate behaviour I want?
Here's what I'm getting from my SQL log from the database:
SET AUTOCOMMIT TRUE /*C19*/SET AUTOCOMMIT FALSE DELETE FROM SCHEDULED_INSTRUCTORS WHERE SCHEDULED_COURSE_ID=1 AND USER_ID=3 //fine DELETE FROM INSTRUCTORS WHERE USER_ID=3 //not good DELETE FROM USERS WHERE USER_ID=3 //not good DELETE FROM SCHEDULED_COURSES WHERE SCHEDULED_COURSE_ID=1 //fine COMMIT SET AUTOCOMMIT TRUE /*C20*/SET AUTOCOMMIT FALSE
And what happens when you remove the hibernate delete-orphan cascade option? and then from there what happens when you remove the PERSIST cascade option. Because you have your mapping with the join table, which is good, it should automatically remove records from the join table and not affect the Instructors.
line. And ran the app. No change. Then I removed the CascadeType.PERSIST option and ran the app again. Still no change.
When I removed everything regarding cascading all together, it worked! Only the record in the SCHEDULED_INSTRUCTORS table was deleted. Which is what I wanted. So, the annotation really needed to just be:
I thought the cascading options had to be there in order to affect the SCHEDULED_INSTRUCTORS table, but I guess not. I guess hibernate is smart enought to know to only affect the one table and no others?
The important thing to Hibernate is that it is a ???ToMany and you have a Collection.
Hibernate is good in that it is a join table and hides it from your object model. However, in a lot of cases that join table will store extra information and you might want a Java Object to map to that join table and then your cascade options will be important.
Joined: Sep 24, 2003
I'm glad you brought that up... In the same class, ScheduledCourse, I have another collection of Enroll objects. The Enroll class represents a Join Table as well which contains additional fields. I used the example as presented in the book Java Persistence with Hibernate Chapter 7 page 304, regarding "Mapping the join table to an intermediate entity".
Again, I'm trying to test the delete feature by running my test app to see what affect hibernate has on the ScheduledCourse instance which also includes this collection of Enroll objects, like so:
The Student class has the same at its end:
The Enroll class looks like so:
So, imagine if you will, that I've enrolled three students into the ScheduledCourse instance. This means the Enroll table has these three records in it tying in the students with the ScheduledCourse.
Once again, when I call this in my test app:
EntityManager em = ...; ScheduledCourse sc = em.find(ScheduledCourse.class, new Long(1)); em.remove(sc);
Naturally, one would expect that those records in the Enroll table to disappear. But they don't. I tried eliminating the cascading options altogether, as I did for the collection of Instructors, anything I do has no affect.
Can you explain what needs to be done in this scenario to make it work?