Hibernate – Saving a Many to Many relationship.

I am mapping my object model using Hibernate annotations.  I came across a issue when trying to save a entity bean to a table, along with a Many-to-Many relationship to a row in another table.  The exception I got was

javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: au.com.ffff.model.Activity

The Activity table is the other table.  The one I just want to save a relationship to.  To save a new entity you need to use entityManager.persist.  To save (update) an existing entity you need to use entityManager.merge.  The entity I am saving is new, but it has a relationship with an existing entity.  The solution is to use persist to save the entity without the relationship, then add the relationship and call merge.

My tables

Event
id
other fields

EventActivity
eventId
activityId

Activity
id
other fields

My entity beans

@Entity
public class Event implements Serializable {

@Id
@GeneratedValue
private Integer id;

@ManyToMany (cascade=CascadeType.ALL,
fetch=FetchType.EAGER)
@JoinTable(name=”EventActivity”,
joinColumns=@JoinColumn(name=”eventId”),
inverseJoinColumns=@JoinColumn(name=”activityId”))
private Set<Activity> activities;

other fields
}

@Entity
public class Activity implements Serializable {

@Id
@GeneratedValue
private Integer id;

@ManyToMany (mappedBy=”activities”,
fetch=FetchType.LAZY)
private Set<Event> events;

other fields
}

My code

Action class method

some code

// hibernate won’t just let me create an instance
// I have to get it from the DB first.
Activity activity = activityService.find(activityId);
Set<Activity> activities = new HashSet<Activity>();
activities.add(activity);
event.setActivities(activities);

eventService.save(event);

more code

Service implementation

some code

Set<Activity> activities = event.getActivities();
// have to do this to keep hibernate happy.
event.setActivities(null);
// this inserts the row into the event table
em.persist(event);

event.setActivities(activities);
// this inserts the row into the eventactivity table
// and would also update the activty table if it had changed
em.merge(event);

more code

This works for me.  It does mean that I have to do one more database query than I really need to.  I can’t just create a Activity instance and set the id (or hibernate will try to update all the other activity fields to null when I call merge).  I have to get the whole activity object out of the database even though the only value I need from it is the id to go into the activityId column of the EventActivity table.

Advertisements
This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s