Hi Joe, I'm a little confused by your example. Maybe this isn't directly related to the problem, but why are you using the merge() method? If you are working with Entities are already part of the persistence context (I'm assuming all of your find processing is happening withing a CMT), then all of the Users and Groups are already managed. There is no need to call merge() on these Entities. Any changes to these Entities should be detected by the OpenJPA runtime and processed accordingly.
(I know that the comment below indicates that the User and Groups are unmanaged, but based on the statements that this is an EJB method and your EM must have been injected into this EJB, the find operation as currently coded would make the User and Groups managed. That's the way I am reading the code.) The merge() method is for merging detached Entities into the current persistence context. Granted, you should still be able to call merge() on a managed entity, but it's not the proper programming model usage. Can you help clarify this usage and the expected behavior? Thanks. Kevin On Mon, Oct 4, 2010 at 9:31 AM, joe <[email protected]> wrote: > Hi, > > I try to update a many to many relationship between a User and Group > entity. Lets say the user is member of an additional group. > A simple entityManager.merge(user) > does not work cause in my case the User entity is not the owner-side. > Ok, so i coded this: > > EJB method: > // the user entity comes from the GUI so the user and the related > // groups are unmanaged > public void updateUser(User editedUser) > { > User existingUser = entityManager.find(User.class, editedUser.getId()); > > List<Group> groupsOfExistingUser = existingUser.getGroups(); > List<Group> groupsOfEditedUser = editedUser.getGroups(); > > List<Group> addedGroups = determineAddedGroups(groupsOfEditedUser, > groupsOfExistingUser); > List<Group> removedGroups = determineRemovedGroups(groupsOfEditedUser, > groupsOfExistingUser); > List<Group> intersectionGroups = > determineIntersectionGroups(groupsOfEditedUser, groupsOfExistingUser); > > for (Group group : addedGroups) > { > group.getUsers().add(editedUser); > entityManager.merge(group); > } > > for (Group group : removedGroups) > { > List<User> users = group.getUsers(); > removeUser(users, editedUser.getId()); > entityManager.merge(group); > } > > for (Group group : intersectionGroups) > { > List<User> users = group.getUsers(); > replaceUser(users, editedUser); > entityManager.merge(group); > } > try > { > entityManager.flush(); > } > catch (Exception e) > { > e.printStackTrace(); > } > System.out.println("done"); > } > > > This looks very complicated to me. Is there an easier way? > Abstract away from the complication this code works only in a junit test > using OpenEJB in local server mode, but in production it does not work, i > got the following exception: > > <openjpa-1.2.1-r752877:753278 fatal user error> > org.apache.openjpa.persistence.InvalidStateException: The generated value > processing detected an existing value assigned to this field: > de.test.ejb.common.entity.Group.id. > This existing value was either provided via an initializer or by calling > the setter method. > You either need to remove the @GeneratedValue annotation or modify the code > to remove the initializer processing. > at > org.apache.openjpa.util.ApplicationIds.assign(ApplicationIds.java:483 > ) > at > org.apache.openjpa.util.ApplicationIds.assign(ApplicationIds.java:463 > ) > at > org.apache.openjpa.jdbc.kernel.JDBCStoreManager.assignObjectId(JDBCSt > oreManager.java:744) > ... > > > > @Entity > @Table(name = "USERS") > public class User implements Serializable > { > private Long id; > private Long version; > private String username; > private List<Group> groups; > > @Id > @Column(name = "ID") > @GeneratedValue(strategy = GenerationType.SEQUENCE) > public Long getId() > { > return id; > } > > public void setId(Long id) > { > this.id = id; > } > > @Version > @Column(name = "OPT_LOCK") > public Long getVersion() > { > return version; > } > > public void setVersion(Long version) > { > this.version = version; > } > > @Column > public String getUsername() > { > return username; > } > > public void setUsername(String name) > { > this.username = name; > } > > @ManyToMany(mappedBy = "users", fetch = FetchType.EAGER, cascade = { > CascadeType.PERSIST, CascadeType.MERGE }) > public List<Group> getGroups() > { > return groups; > } > > public void setGroups(List<Group> groups) > { > this.groups = groups; > } > } > > > @Entity > @Table(name = "GROUPS") > public class Group implements Serializable > { > private Long id; > private Long version; > private String name; > private List<User> users; > > @Id > @Column(name = "ID") > @GeneratedValue(strategy = GenerationType.SEQUENCE) > public Long getId() > { > return id; > } > > public void setId(Long id) > { > this.id = id; > } > > @Version > @Column(name = "OPT_LOCK") > public Long getVersion() > { > return version; > } > > public void setVersion(Long version) > { > this.version = version; > } > > public String getName() > { > return name; > } > > public void setName(String name) > { > this.name = name; > } > > @ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.PERSIST, > CascadeType.MERGE }) > @JoinTable(name = "GROUPS_USERS", joinColumns = @JoinColumn(name = > "GROUP_ID", referencedColumnName = "ID"), inverseJoinColumns = > @JoinColumn(name = "USER_ID", referencedColumnName = "ID")) > public List<User> getUsers() > { > return users; > } > > public void setUsers(List<User> users) > { > this.users = users; > } > } > > > > >
