java.lang.IllegalStateException:具有@ManyToMany 3实体的同一实体的多个表示形式

use*_*867 29 java hibernate jpa ejb-3.0 jpa-2.0

我有3个具有ManyToMany关系的实体,如下所示:

角色实体:

@Entity
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer roleID;
    private String roleName;
    private String description;

    @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.EAGER)
    @JoinTable(name = "role_permission", joinColumns = {@JoinColumn(name = "role_id")}, inverseJoinColumns = {@JoinColumn(name = "permission_id")})
    private Set<Permission> permissions = new LinkedHashSet<Permission>();
}
Run Code Online (Sandbox Code Playgroud)

许可实体:

@Entity
public class Permission {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int permissionID;
    private String permissionName;
    private String description;

    @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.EAGER)
    @JoinTable(name = "permission_functionality", joinColumns = {@JoinColumn(name = "permission_id")}, inverseJoinColumns = {@JoinColumn(name = "functionality_id")})
    private Set<Functionality> functionalities = new LinkedHashSet<>();
}
Run Code Online (Sandbox Code Playgroud)

功能实体:

@Entity
public class Functionality {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
}
Run Code Online (Sandbox Code Playgroud)

我做了以下事情:

  1. 我创建了3个功能.

    Functionality1, Functionality2, Functionality3
    
    Run Code Online (Sandbox Code Playgroud)
  2. 然后创建2个权限:

    Permission1 with Functionality1, Functionality2
    
    Permission2 with Functionality2, Functionality3
    
    Run Code Online (Sandbox Code Playgroud)
  3. 然后在创建角色时:

    Role1 with Permission1 and Permission2 
    
    Run Code Online (Sandbox Code Playgroud)

    java.lang.IllegalStateException:正在合并同一实体[com.persistence.entity.admin.Functionality#1]的多个表示.分离:[com.persistence.entity.admin.Functionality@4729256a]; 分离:[com.persistence.entity.admin.Functionality@56ed25db]

use*_*867 36

通过删除Permission实体上的CascadeType.MERGE来修复它

  • 尝试使用Hibernate级联注释而不是JPA注释。例如,@ Cascade(CascadeType.SAVE_UPDATE)将替换{CascadeType.PERSIST,CascadeType.MERGE}。检查本文:[JPA和Hibernate注释常见错误](https://www.mkyong.com/hibernate/cascade-jpa-hibernate-annotation-common-mistake/) (3认同)
  • 如果我想合并现有实体,这有什么影响?当我删除 `CascadeType.MERGE` 时会发生什么? (3认同)

Sur*_*non 24

正确的解决方案是升级到hibernate 4.2.15/4.3.6或更高版本,并将以下行添加到persistence.xml:

<property name="hibernate.event.merge.entity_copy_observer" value="allow"/>

  • 此属性适用于整个持久性上下文,仅应用于测试目的.如果将其设置为"允许"或"日志",Hibernate将继续按顺序合并两个分离的实体.但是,未定义合并的顺序.因此,这可能会导致意外数据损坏.正确的解决方案是修复实体关系. (11认同)
  • @VHS您能解释一下我删除`CascadeType.MERGE`会发生什么吗?我将其视为无处不在的答案,但我敢打赌,这是一个具有副作用的重大变化。 (3认同)

Gui*_*ter 15

就像其他人的答案基于HHH-9106 一样,但是,因为我使用的是带有基于 Java 的注释的 Spring Boot,所以我不得不在以下内容中使用application.properties

spring.jpa.properties.hibernate.event.merge.entity_copy_observer=allow
Run Code Online (Sandbox Code Playgroud)


小智 12

检查你的equals和hashCode方法,确保它是一致的并且正确定义.例如,我在计算hashCode时复制并错误地粘贴了另一个类,这导致对象永远不会与自身相等:(.

  • 很好的答案!谢谢你!IntelliJ 有一个生成 `equals` 和 `hashCode` 的过程,你可以在他们的网站上查看(https://www.jetbrains.com/help/idea/generate-equals-and-hashcode.html)。 (2认同)

小智 6

我也遇到了同样的问题,并通过在application.yaml文件中添加一些配置来解决了这个问题。

  jpa:
    properties:
      hibernate:
        enable_lazy_load_no_trans: true
        event:
          merge:
            entity_copy_observer: allow
Run Code Online (Sandbox Code Playgroud)

在这里看到它如何使用spring-boot和JPA持久化包含另一个未持久实体的多个相同实例的新实体?


Aru*_*rio 5

我可以通过更换来修复它

cascade = CascadeType.All
Run Code Online (Sandbox Code Playgroud)

casecade={CascadeType.PERSIST,CascadeType.REMOVE}
Run Code Online (Sandbox Code Playgroud)