These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: Issues with ManyToMany Relationship
PostPosted: Fri Aug 18, 2006 9:13 am 
Newbie

Joined: Fri Aug 18, 2006 9:11 am
Posts: 7
Hi,

I have defined a many to many relationship between two classes, viz.
Event and Person (defined in a separate database table person_event).
The code of these classes is listed at the end. Now, suppose I want to
delete a person, so all its related associations with events must also
get deleted from the person_event table. In other words, I want cascade
ON DELETE.

Lets consider a scenario.
- The "events" table contains three events identified by id=1, 2, 3.
- The "person" table contains two persons identified by id=4, 5.
- The "person_event' table containing associations like 1-4, 2-4, 3-5

Now, suppose I delete event 1 using Hibernate.delete(), then not only
does it delete event1, and association person_event1-4, but also the
person4 and subsequently, person_event2-4 and event2.

I dont understand why this is happening. Could someone please explain
where I am committing a mistake.

Thanks in advance

- Abhishek

Event and Person Class

package test;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name="events")
public class Event implements Serializable {
private Long id;
private String title;
private Date date;

public Event() {
}

@Id @GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}

private void setId(Long id) {
this.id = id;
}

@Temporal(TemporalType.TIMESTAMP)
public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}
private Set<Person> participants = new HashSet<Person>();

@ManyToMany(
cascade={CascadeType.ALL},
mappedBy="events",
targetEntity=Person.class
)
public Set<Person> getParticipants() {
return participants;
}

public void setParticipants(Set<Person> participants) {
this.participants = participants;
}
}

package test;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name="person")
public class Person implements Serializable {
private Long person_id;
private int age;
private String firstname;
private String lastname;

public Person() {}

@Id @GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return person_id;
}

public void setId(Long id) {
this.person_id = id;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getFirstname() {
return firstname;
}

public void setFirstname(String firstname) {
this.firstname = firstname;
}

public String getLastname() {
return lastname;
}

public void setLastname(String lastname) {
this.lastname = lastname;
}

private Set<Event> events = new HashSet<Event>();

@ManyToMany(
targetEntity=Event.class,
cascade={CascadeType.ALL}
)
@JoinTable(
name="person_event",
joinColumns={@JoinColumn(name="person_id")},
inverseJoinColumns={@JoinColumn(name="event_id")})
// Defensive, convenience methods
protected Set<Event> getEvents() {
return events;
}

protected void setEvents(Set<Event> events) {
this.events = events;
}

public void addToEvent(Event event) {
this.getEvents().add(event);
event.getParticipants().add(this);
}

public void removeFromEvent(Event event) {
this.getEvents().remove(event);
event.getParticipants().remove(this);
}
}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 18, 2006 4:22 pm 
Regular
Regular

Joined: Fri Aug 18, 2006 2:40 pm
Posts: 51
Location: Metz, France
The behaviour you described is not CASCADE on DELETE.

CascadeType.REMOVE: cascades the remove operation to associated entities if delete() is called

You only want the relationship to be deleted when one of the participant is removed, i.e. if you remove a PERSON the relation to the related EVENT is destroyed.

Hibernate will do that without any special settings.
Using CascadeType.PERSIST would be enough in my opinion.

So if you delete a PERSON, related EVENT is not deleted but relationship is deleted.
If you delete an EVENT, related PERSON is not deleted but relationship is deleted.

Tell me if it helps.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 19, 2006 12:44 am 
Newbie

Joined: Fri Aug 18, 2006 9:11 am
Posts: 7
It worked. Thanks for the help. Could you do me another favor by explaining what exactly the four cascade types mean, so that in future I can use them as desired.

Thanks in advance


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 19, 2006 2:53 am 
Regular
Regular

Joined: Fri Aug 18, 2006 2:40 pm
Posts: 51
Location: Metz, France
You can find a description for each Cascade Types here:
http://www.hibernate.org/hib_docs/annot ... ntity.html

and look for "Transitive persistence with cascading"


....
* CascadeType.PERSIST: cascades the persist (create) operation to associated entities persist() is called or if the entity is managed
* CascadeType.MERGE: cascades the merge operation to associated entities if merge() is called or if the entity is managed
* CascadeType.REMOVE: cascades the remove operation to associated entities if delete() is called
* CascadeType.REFRESH: cascades the refresh operation to associated entities if refresh() is called
* CascadeType.ALL: all of the above

Please refer to the chapter 6.3 of the EJB3 specification for more information on cascading and create/merge semantics.
....


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 19, 2006 3:21 am 
Newbie

Joined: Fri Aug 18, 2006 9:11 am
Posts: 7
The solution of CacadeType.PERSIST worked when I was hadnling the entity using delete() operation, but when I tried using HQL, and making a query, it came up with an exception. Below is the code excerpt.

String hql = "delete from Event where title = 'Your Event'";
query = session.createQuery(hql);
int rowCount = query.executeUpdate();
System.out.println("Rows affected: " + rowCount);
session.close();

And the EXCEPTION it caused.

Caused by: org.postgresql.util.PSQLException: ERROR: update or delete on "events" violates foreign key constraint "fkecd7dd303b90a48b" on "person_event"

at org.postgresql.util.PSQLException.parseServerError(PSQLException.java:139)
at org.postgresql.core.QueryExecutor.executeV3(QueryExecutor.java:152)
at org.postgresql.core.QueryExecutor.execute(QueryExecutor.java:100)
at org.postgresql.core.QueryExecutor.execute(QueryExecutor.java:43)
at org.postgresql.jdbc1.AbstractJdbc1Statement.execute(AbstractJdbc1Statement.java:517)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:50)
at org.postgresql.jdbc1.AbstractJdbc1Statement.executeUpdate(AbstractJdbc1Statement.java:273)
at org.hibernate.hql.ast.exec.BasicExecutor.execute(BasicExecutor.java:75)
... 18 more


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 19, 2006 2:02 pm 
Regular
Regular

Joined: Fri Aug 18, 2006 2:40 pm
Posts: 51
Location: Metz, France
I am very close to your environment (same mapping, same classes)

I got this Foreign key constraints exceptions with session.delete() AND HQL.

The problem stay the same, delete in events table is done without deleting row in relation table.

Now I am convinced there is something wrong in the annotations you used to describle relationship between events and person.
I have never used annotations before so I must take a deeper look at it.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.