• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Jeanne Boyarsky
  • Ron McLeod
Sheriffs:
  • Paul Clapham
  • Liutauras Vilda
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
Bartenders:

unwanted cascade delete behaviour

 
Ranch Hand
Posts: 237
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi there,

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:

EntityManager em4 = emf.createEntityManager();
EntityTransaction tx4 = em4.getTransaction();
tx4.begin();
ScheduledCourse sc = em2.find(ScheduledCourse.class, new Long(1));
em4.remove(sc);
tx4.commit();
em4.close();

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

Please advise,

Alan
 
ranger
Posts: 17347
11
Mac IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.

Mark
 
Alan Shiers
Ranch Hand
Posts: 237
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Mark,

I tried your suggestion. First I commented out the

@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)

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:

@OneToMany
@org.hibernate.annotations.CollectionOfElements
@JoinTable(name = "SCHEDULED_INSTRUCTORS", joinColumns = {@JoinColumn(name = "SCHEDULED_COURSE_ID")}, inverseJoinColumns ={@JoinColumn(name = "USER_ID")})
private Collection<Instructor> INSTRUCTORS_SCHEDULED = new ArrayList<Instructor>();

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?

By the way, is this a OneToMany or ManyToMany relationship?

Alan

[ February 14, 2007: Message edited by: Alan Shiers ]

[ February 14, 2007: Message edited by: Alan Shiers ]
[ February 14, 2007: Message edited by: Alan Shiers ]
 
Mark Spritzler
ranger
Posts: 17347
11
Mac IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Alan Shiers:

By the way, is this a OneToMany or ManyToMany relationship?



Yes.

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.

Mark
 
Alan Shiers
Ranch Hand
Posts: 237
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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?

Alan
 
I can't renounce my name. It's on all my stationery! And hinted in this tiny ad:
New web page for Paul's Rocket Mass Heaters movies
https://coderanch.com/t/785239/web-page-Paul-Rocket-Mass
reply
    Bookmark Topic Watch Topic
  • New Topic