views:

911

answers:

3

I have an error being thrown on deleting an entity. I have users in only one group at a time, so it's a ManyToOne relationship on the User class. In the page class I have a property group:

@Property @Persist private Group group;

that is populated on page activation:

public void onActivate(Group g) {
    group = g;
}

When the deletion ActionLink is clicked, this is executed:

@CommitAfter
public ListBillingUserGroups onActionFromDelete() {
    for (User u : getUsersInGroup())
        u.setGroup(null);
    session.delete(group);
    return listPage;
}

public List<User> getUsersInGroup() {
    Criteria c = session.createCriteria(User.class)
        .add(eq("company", ctx.getUser().getCompany()))
        .add(eq("group", group));
    return c.list();
}

When the group has no users in it, then the delete happens, and the browser redirects to the list page (as expected). However, if the group has users in, then I get an exception thrown from hibernate, with message:

a different object with the same identifier value was already associated with the session: [my.package.Group#10]

with a stacktrace:

org.hibernate.engine.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:613)
org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:121)
org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:74)
org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:793)
org.hibernate.impl.SessionImpl.delete(SessionImpl.java:771)
... my code ...

The error still happens if I replace the onActionFromDelete method with:

@CommitAfter
public ListBillingUserGroups onActionFromDelete() {
    for (User u : getUsersInGroup())
        System.out.print(" >> " + u.getGroup());
    session.delete(group);
    return listPage;
}

the error still happens (as opposed to getting the constraint voilation exception), but if I replace it with:

@CommitAfter
public ListBillingUserGroups onActionFromDelete() {
    session.delete(group);
    return listPage;
}

I get the constraint violation exception.

So it behaves as if calling the getAllUsersInGroup method changes the group object to another object representing the same entity (same class, same id). Any hints as to what I am doing wrong ?

A: 

I don't know for Tapestry, but in Hibernate ...

This message happens when you try to delete an entity (pair : class and id) using an object A, while the Hibernate session already has an instance B that corresponds to this pair.

For example, loading your users loads the entity (possibly lazy). So to delete the group, you should use the group instance (the exact java object) that was used by Hibernate as the group of the users. If you use another instance, you will get that exception.

KLE
I think that I am using the same object. I have a property on the page class that is populated by tapestry when the page is requested (the group I mentioned). I am using that group in the query to list all the users in the group with the criteria API, and then trying to delete it. I guess i could rephrase my question as "How come they're not the same object ?"
l0st3d
@IOst3d I suggest you make sure : open the debugger, and check if it is the same instance (use the java object identifier that shows in the debugger). This point is essential.
KLE
+2  A: 

I think you should try:

@Persist("entity")

because the @Pesist annotation (without params) store your Group object in the session and by the time you delete it, is a detached object.

http://tapestry.apache.org/tapestry5/tapestry-hibernate/userguide.html

the alternative is to store the Group id (instead of the Group Object) and retrieve the object in the onActivate method.

César L
A: 

There is a HowTo about this topic at the Tapestry5 Wiki:

http://wiki.apache.org/tapestry/Tapestry5AvoidingDifferentObjectWithSameIDExceptions

HTH

AlexBottoni