Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
395 views
in Technique[技术] by (71.8m points)

java - How to persist @ManyToMany relation - duplicate entry or detached entity

I want to persist my entity with ManyToMany relation. But i have some problem during persisting process.

My entities :

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

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long userId;

    @Column(name = "NAME", unique = true, nullable = false)
    String userName;

    @Column(name = "FORNAME")
    String userForname;

    @Column(name = "EMAIL")
    String userEmail;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "USER_USER_ROLES", joinColumns = @JoinColumn(name = "ID_USER"), inverseJoinColumns = @JoinColumn(name = "ID_ROLE"))
    List<UserRoles> userRoles = new ArrayList<UserRoles>();

    // getter et setter
}

and

@Entity
@Table(name = "USER_ROLES")
public class UserRoles implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long userRolesId;

    @Column(unique = true, nullable = false, name = "ROLE_NAME")
    String roleName; 

    // getter et setter
}

Service code :

User user = new User();
UserRoles role;
try {
    role = userRolesServices.getUserRoleByName("ROLE_USER"); // find jpql - transaction
} catch (RuntimeException e) {
    LOGGER.debug("No Roles found");
    role = new UserRoles("ROLE_USER"); // create new
}
user.addUserRole(role);
user.setUserName(urlId);
user.setUserForname(fullName);
user.setUserEmail(email);
userServices.createUser(user); // em.persist(user) - transaction

First time, when I try to persist a User with UserRoles "ROLE_USER", no problem. User and UserRoles and join tables are inserted.

My problem is when I try to persist a second User with the same UserRoles. I check if the UserRoles exists by finding it (userRolesServices.getUserRoleByName(...)). If exists -> add this UserRoles to User list (id + role name) else i create a new one (only role name).

By when I try to persist the second User, i obtain the following exception : "detached entity to persist : .....UserRoles" (maybe because getUserRoleByName is performed in another transaction)

If I do not use getUserRoleByName (only *new UserRoles("ROLE_USER");*), i obtain the following exception : "...ConstraintViolation : Duplicated entry for 'ROLE_NAME' ..."

So, how to properly persist an entity with @ManyToMany relation ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For above problem I would say your entity relationship cascade is wrong. Consider this: A user can have multiple roles but there can be fixed number of roles that can exist in the system. So CASCADE ALL from User entity does not make any sense, since life cycle of UserRoles should not depend on User entity life cycle. E.g. when we remove User, UserRoles should not get removed.

detached entity to persist exception will only occur when you are passing object which has primary key already set to persist.

Remove cascade and your problem will be solved now only thing you will need to decide is how you are going to insert User roles. According to me there should be separate functionality to do so.

Also do not use ArrayList, use HashSet. ArrayList allows duplicates.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...