LuckyLuke
LuckyLuke

Reputation: 49047

Transaction aborted when trying to persist user

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;

       ....

}

Upvotes: 1

Views: 8521

Answers (2)

user935265
user935265

Reputation: 254

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.

Upvotes: 0

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

Upvotes: 1

Related Questions