更新多对多关系中的实体

Posted

技术标签:

【中文标题】更新多对多关系中的实体【英文标题】:updating an entity in many-to-many relationship 【发布时间】:2018-02-25 21:48:16 【问题描述】:

我有一个将 JPA 与 Hibernate 和 mysql 数据库一起使用的 Spring 项目。数据库包括三个表:Users、Roles 和多对多连接表 UserRoles。 下面是表的对应类。

ApplicationUser.java

@Entity
@Table(name = "APPLICATION_USER")
public class ApplicationUser extends ExtAuditInfo 

public static final Long SYSTEM_USERID = 1000L;


@Id
@Column(name = "APPLICATION_USER_ID")
private long applicationUserId;

@Column(name = "LOGIN_NAME")
private String loginName;

@Column(name = "LAST_NAME")
private String lastName;

@Column(name = "FIRST_NAME")
private String firstName;

@Column(name = "MIDDLE_NAME")
private String middleName;

@OneToMany(mappedBy = "id.applicationUser", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<UserRole> roles =new ArrayList<>();

//get and set methods

Role.java

@Entity
@Table(name = "ROLE")
@NamedQueries(
@NamedQuery(name = "Role.getRoleById", query = "select r from Role r where r.roleId =:roleId"))
public class Role extends AuditInfo 

@Id
@Column(name="ROLE_ID")
private long roleId;

@Column(name="ACTIVE_FLAG")
private String activeFlag;

@Column(name="ROLE_NAME")
private String roleName;

@OneToMany(mappedBy = "id.role", fetch = FetchType.LAZY)
private List<UserRole> users = new ArrayList<>();

//get and set methods

UserRole.java

@Entity
@AssociationOverrides(
        @AssociationOverride(name = "id.applicationUser",
                joinColumns = @JoinColumn(name = "APPLICATION_USER_ID")),
        @AssociationOverride(name = "id.role",
                joinColumns = @JoinColumn(name = "ROLE_ID")) )
@Table(name = "USER_ROLE")
public class UserRole extends ExtAuditInfo implements Serializable
    @EmbeddedId
    private UserRoleID id = new UserRoleID();

    @Column(name="USER_ROLE_VER")
    private long userRoleVer;

    public UserRole()
    

    @Transient
    public ApplicationUser getApplicationUser() 
        return this.id.getApplicationUser();
    

    public void setApplicationUser(ApplicationUser applicationUser) 
        this.id.setApplicationUser(applicationUser);
    

    public long getUserRoleVer() 
        return this.userRoleVer;
    

    public void setUserRoleVer(long userRoleVer) 
        this.userRoleVer = userRoleVer;
    

    @Transient
    public Role getRole()  return this.id.getRole(); 

    public void setRole(Role role)  this.id.setRole(role); 

UserRoleID.java

@Embeddable
public class UserRoleID implements Serializable 

    @ManyToOne(cascade = CascadeType.ALL)
    private ApplicationUser applicationUser;

    @ManyToOne(cascade = CascadeType.ALL)
    private Role role;

    private static final long serialVersionUID = 1L;

    public UserRoleID() 
    

    public ApplicationUser getApplicationUser() 
        return this.applicationUser;
    

    public void setApplicationUser(ApplicationUser applicationUser) 
        this.applicationUser = applicationUser;
    

    public Role getRole() 
        return this.role;
    

    public void setRole(Role role) 
        this.role = role;
    

现在,当我创建一个具有 viewer 角色的示例用户时,记录被插入到 Application_user 和 User_Role 表中,但是当我尝试更新用户的角色时,它正在添加一个新的角色给用户,而不是更新现有的角色。

这就是我正在做的事情

@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void updateRole(ApplicationUser appUser, long roleId)
        EntityManager em=getEntityManager();
        TypedQuery<Role> query = em.createNamedQuery("Role.getRoleById", Role.class);
        query.setParameter("roleId",roleId);
        Role r = query.getSingleResult();
        UserRole userRole= appUser.getRole().get(0);
        userRole.setRole(r);
        em.merge(userRole);
        em.flush();
        em.detach(userRole);

任何想法,如何更新现有角色而不是在 user_role 表中创建新角色?

【问题讨论】:

【参考方案1】:

您正在为用户分配新角色,因此在 user_role 表中添加了一条新记录,并删除了旧的 user_role 条目。这是正确的行为。 所以不是你所谓的“更新用户角色”。

更新: 多对多关系时需要手动删除角色。

appUser.getRoles().remove(userRole);
em.remove(userRole);
UserRole newUserRole = new UserRole();
newUserRole.setRole(r);
appUser.getRoles().add(newUserRole);

【讨论】:

旧角色没有被删除,user_role 表现在有两条记录 多对多关系需要手动删除角色。

以上是关于更新多对多关系中的实体的主要内容,如果未能解决你的问题,请参考以下文章

如何在不更新具有多对多关系的子实体的情况下保留父实体?

Hibernate多表关系配置——多对多对关系映射

EF更新多对多关系表中记录的时候,无法更新关系表的问题。

具有多个多对多关系的休眠批处理事务

实体框架中的多对多关系导致无限循环

Remove() 不适用于实体框架中的多对多关系