【问题标题】:spring boot data jpa DataIntegrityViolationException EntityExistsException春季启动数据 jpa DataIntegrityViolationException EntityExistsException
【发布时间】:2020-08-19 14:38:49
【问题描述】:

有两个实体PermissionRole@ManyToMany 有关系;我想在他们的连接表中添加一些额外的字段,我在这篇文章 enter link description here 之后编码,这里是我的代码:
角色实体

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@GenericGenerator(name = "jpa-uuid", strategy = "uuid")
public class Role {

    @Id
    @GeneratedValue(generator = "jpa-uuid")
    private String id;

    @JsonIgnore @ToString.Exclude
    @OneToMany(mappedBy = "role",cascade = CascadeType.ALL,orphanRemoval = false,fetch = FetchType.EAGER)
    private Set<RolePermission> role_permission;

    public void addPermission(Permission permission){
        RolePermission rolePermission  = new RolePermission(this,permission);
        role_permission.add(rolePermission);
        permission.getRole_permission().add(rolePermission);
    }
    public void removePermission(Permission permission){
        for(Iterator<RolePermission> iterator = role_permission.iterator();iterator.hasNext();){
            RolePermission rolePermission = iterator.next();
            if(rolePermission.getRole().equals(this) && rolePermission.getPermission().equals(permission)){
                iterator.remove();
                rolePermission.getRole().role_permission.remove(rolePermission);
                rolePermission.setRole(null);
                rolePermission.setPermission(null);
            }
        }
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Role role = (Role) o;
        return Objects.equals(id, role.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}


权限实体


@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@GenericGenerator(name = "jpa-uuid", strategy = "uuid")
public class Permission {
    @Id
    @GeneratedValue(generator = "jpa-uuid")
    private String id;

    @JsonIgnore @ToString.Exclude
    @OneToMany(mappedBy = "permission",cascade = CascadeType.ALL,orphanRemoval = true,fetch = FetchType.EAGER)
    private Set<RolePermission> role_permission;

    public void addRole(Role role){
        RolePermission rolePermission  = new RolePermission(role,this);
        role_permission.add(rolePermission);
        role.getRole_permission().add(rolePermission);
    }
    public void removeRole(Role role){
        for(Iterator<RolePermission> iterator = role_permission.iterator(); iterator.hasNext();){
            RolePermission rolePermission = iterator.next();
            if(rolePermission.getRole().equals(role) && rolePermission.getPermission().equals(this)){
                iterator.remove();
                rolePermission.getRole().getRole_permission().remove(rolePermission);
                rolePermission.setRole(null);
                rolePermission.setPermission(null);
            }
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Permission that = (Permission) o;
        return Objects.equals(id, that.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

角色权限密钥


@Embeddable
@Setter
@Getter
@NoArgsConstructor
public class RolePermissionKey implements Serializable {
    private static final long serialVersionUID = 4686642987484483168L;
    @Column(name = "role_id")
    private String role_id;
    @Column(name = "permission_id")
    private String permission_id;

    public RolePermissionKey(String roleId, String permissionId) {
        this.role_id=roleId;
        this.permission_id=permissionId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RolePermissionKey that = (RolePermissionKey) o;
        return role_id.equals(that.role_id) &&
                permission_id.equals(that.permission_id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(role_id, permission_id);
    }
}

带有额外字段的关系表

@Entity
@Setter
@Getter
@NoArgsConstructor
public class RolePermission implements Serializable {
    private static final long serialVersionUID = 8274025418699729303L;

    @EmbeddedId
    RolePermissionKey id;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("role_id")
    Role role;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("permission_id")
    Permission permission;

    Date create_date  =new Date();


    public RolePermission(Role role,Permission permission) {
        this.role=role;
        this.permission=permission;
        this.id = new RolePermissionKey(role.getId(),permission.getId());
        this.create_date=new Date();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RolePermission that = (RolePermission) o;
        return Objects.equals(role, that.role) &&
                Objects.equals(permission, that.permission);
    }

    @Override
    public int hashCode() {
        return Objects.hash(role, permission);
    }
}

测试代码

        Role role5 = roleRepository.findByTitle("Role5");
        Permission permission6 = permissionRepository.findByTitle("Permission6");
        role5.addPermission(permission6);
        permission6.addRole(role5);
        roleRepository.save(role5);
        permissionRepository.save(permission6);

然后,我在四个地方使用了相同的测试代码进行测试:
1.一个类实现了ApplicationRunner;在spring boot启动前初始化数据,no exception
2.一个 Spring Boot 测试类 @SpringBootTest;no exception
3.控制器类 @Controller ; exception thrown
4.服务类 @Service ; exception thrown
这里例外: 2020-05-05 09:11:35.952 WARN 17000 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.dao.DataIntegrityViolationException: A different object with the same identifier value was already associated with the session : [com.xxx.model.authentication.RolePermission#com.xxx.model.authentication.RolePermissionKey@9e2c8771]; nested exception is javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.xxx.model.authentication.RolePermission#com.xxx.model.authentication.RolePermissionKey@9e2c8771]]
现在我很困惑问题是代码还是其他问题。我在 1,2 中使用了测试代码来添加之间的关系 一个角色和一个权限susscessfully,并得到了预期的结果。但代码在3,4中不起作用。
我需要一些提示和建议;顺便问一下,有没有使用spring data jpa的开源真实世界项目值得学习? ,谢谢。

#################################################################
感谢@Olivier Depriester 的帮助。 我在调试模型中研究了 Role 和 Permission Entity 中 RolePermission Set 的元素; 维护两个实体关系的集合类型是set,我已经覆盖了equals()hashCode() 方法可以确保具有相同 ID 的关系实体(RolePermission)不会出现在同一个集合中。 在save() 执行之前,Set of Role 和 Permision 中实际上只包含一个 RolePermission 对象。 在测试代​​码中,有两个.save() action,即使我注释其中一个,也会抛出异常。 我想知道cascade 是否有问题。 奇怪的是,测试代码可以在某处成功执行。

【问题讨论】:

    标签: hibernate jpa


    【解决方案1】:

    当您调用role5.get().addPermission(permission6); 时,您会为role5permission6 创建并保留(*)RolePermission

    当您调用permission6.addRole(role5); 时,您会为role5permission6 创建并持久化另一个RolePermission

    ==> 例外:会话中具有相同哈希码的同一实体的 2 个实例。

    (*) 当您将一个项目添加到一个持久化对象的属性时,该项目会自动持久化。当您从他们的存储库中获得 role5permission6 时,它们是持久对象

    因此,您需要修改代码以创建 1 个单独的 RolePermission,您可以将其分配给 RolePermission

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-25
      • 2020-05-17
      • 1970-01-01
      • 2016-01-30
      • 2017-06-25
      • 2013-11-12
      • 2020-02-20
      • 1970-01-01
      相关资源
      最近更新 更多