1
votes

I am trying to save an user. The user entity and group entity has a bi-directional many-to-many relationship. However the groups are already saved in the database (only two though: administrator and user).

Here I just "fake" the group which already exists because I thought that would work. I can't add the cascade = CascadeType.PERSIST to the user because then it would save the group again, causing duplicate data. How would I fix this?

From the EJB

public void persistAsUser(User user) {
    Group group = new Group(2L, "user");
    user.addGroup(group);

    userRepository.persist(user);
}

javax.ejb.EJBException: Transaction aborted

Caused by: java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST:


Here are the entities:

    @Entity
    @Table(name = "app_user")
    public class User implements Serializable {

        public static final String ALL = "User.all";

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String firstName;
        private String lastName;
        private Integer age;
        private String username;
        private String email;
        private String password;

        @ManyToMany(mappedBy = "users")
        private List<Group> groups;

        ....

public void addGroup(Group group) {

    if (!getGroups().contains(group)) {
        getGroups().add(group);
    }

    if (!group.getUsers().contains(this)) {
        group.getUsers().add(this);
    }
}
}

and

@Entity
    public class Group implements Serializable {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String groupName;

        @ManyToMany
        @JoinTable(joinColumns = {@JoinColumn(name="group_id")}, inverseJoinColumns = {@JoinColumn(name="user_id")})
        private List<User> users;

       ....

}
2
can't you just not populate the groups property in the User entity? - Gonzalo Garcia Lasurtegui
But I am doing that? I have added a group to the user, but I don't persist it because it is already persisted in the database. - LuckyLuke
set groups to null, that's what I am saying - Gonzalo Garcia Lasurtegui
And then how would the user know which group he belongs to? How would JPA know how to map the userid and groupid in the join table? - LuckyLuke
Then what I would do is retrieve the group you want to add the user to, add the user, and persist the group. You obviously need to indicate cascading for merge in the Group -> User relationship. - Gonzalo Garcia Lasurtegui

2 Answers

1
votes

This issue usually happens when

  • you have bidirectional associations that are not populated in both sides
  • you have a managed (User) entity referencing an unmanaged one (Group).

If you don't want to persist Group, just set groups to null, as per in my comment.

However, if you want to associate the User to the Group, one option would be

  1. load the Group you want to add the user to
  2. Add the User to the Group and viceversa.
  3. merge the Group

Remember to mark the Group -> User relationship as CascadeType.MERGE

0
votes

By placing the mappedBy attribute in the User class, you are saying that the Group class is responsible for persisting the association.

Since the relationship is bi-directional, you can specify either side as the owning side of the relationship.

Try moving the mappedBy attribute to the Group class's ManyToMany annotation, and then persist the User as you were.