找到了对集合org.hibernate.HibernateException的共享引用

nig*_*2k1 59 java grails groovy hibernate grails-orm

我收到此错误消息:

error:找到对集合的共享引用:Person.relatedPersons

当我试图执行时addToRelatedPersons(anotherPerson):

person.addToRelatedPersons(anotherPerson);
anotherPerson.addToRelatedPersons(person);

anotherPerson.save();
person.save();
Run Code Online (Sandbox Code Playgroud)

我的域名:

Person {

 static hasMany = [relatedPersons:Person];

}
Run Code Online (Sandbox Code Playgroud)

知道为什么会这样吗?

Chs*_*y76 63

当您尝试持久存在多个共享相同集合引用的实体实例(即集合标识与集合相等性)时,Hibernate会显示此错误.

请注意,这意味着同样的集合,而不是集合元素-换句话说,relatedPersons在两个personanotherPerson必须相同.也许你在加载实体后重置那个集合?或者您已使用相同的集合实例初始化两个引用?

  • 发现了问题.输入person.relatedPerson = anotherPerson我犯了一个错误; 代码中的某个地方.... doh. (4认同)
  • 是的,但是为什么冬眠将此视为问题?一个实体具有一个类似于ManyToMany字段的集合,并且该值是通过从另一个实体中查找来设置的。 (2认同)

dgt*_*dgt 50

我有同样的问题.在我的例子中,问题是有人使用BeanUtils将一个实体的属性复制到另一个实体,因此我们最终有两个实体引用同一个集合.

鉴于我花了一些时间研究这个问题,我建议如下清单:

  • 查找类似的场景entity1.setCollection(entity2.getCollection())getCollection返回对集合的内部引用(如果getCollection()返回集合的新实例,那么您不必担心).

  • 看看是否clone()已正确实施.

  • 寻找BeanUtils.copyProperties(entity1, entity2).

  • @vashishth 早些时候,我在做`entity1.setCollection(entity2.getCollection())`。我通过`entity1.setCollection(new HashSet(entity2.getCollection()))`解决了它 (3认同)

Mir*_*mas 6

练习说明。如果您尝试保存对象,例如:

Set<Folder> folders = message.getFolders();
   folders.remove(inputFolder);
   folders.add(trashFolder);
   message.setFiles(folders);
MESSAGESDAO.getMessageDAO().save(message);
Run Code Online (Sandbox Code Playgroud)

您不需要将更新的对象设置为父对象:

message.setFiles(folders);
Run Code Online (Sandbox Code Playgroud)

简单保存您的父对象,如:

Set<Folder> folders = message.getFolders();
   folders.remove(inputFolder);
   folders.add(trashFolder);
   // Not set updated object here
MESSAGESDAO.getMessageDAO().save(message);
Run Code Online (Sandbox Code Playgroud)


Met*_*FoX 6

我经历过一个重现此类问题的好例子。也许有一天我的经验会对某人有所帮助。

简洁版本

检查容器的 @Embedded Id 是否存在可能的冲突。

长版

当Hibernate实例化集合包装器时,它会在内部Map中通过CollectionKey搜索已经实例化的集合。

对于带有@Embedded id的Entity,CollectionKey包装EmbeddedComponentType并使用@Embedded Id属性进行相等性检查和hashCode计算。

因此,如果您有两个具有相同 @Embedded Id 的实体,Hibernate 将实例化并通过第一个键放置新集合,并为第二个键找到相同的集合。因此具有相同 @Embedded Id 的两个实体将使用相同的集合填充。

例子

假设您有一个包含惰性贷款集的帐户实体。并且Account有@Embedded Id由几个部分(列)组成。

@Entity
@Table(schema = "SOME", name = "ACCOUNT")
public class Account {
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "account")
    private Set<Loan> loans;

    @Embedded
    private AccountId accountId;

    ...
}

@Embeddable
public class AccountId {
    @Column(name = "X")
    private Long x;
    
    @Column(name = "BRANCH")
    private String branchId;
    
    @Column(name = "Z")
    private String z;

    ...
}
Run Code Online (Sandbox Code Playgroud)

然后假设 Account 具有由 @Embedded Id 映射的附加属性,但与其他实体 Branch 相关。

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "BRANCH")
@MapsId("accountId.branchId")
@NotFound(action = NotFoundAction.IGNORE)//Look at this!
private Branch branch;
Run Code Online (Sandbox Code Playgroud)

可能会发生这样的情况:帐户到 Brunch 关系 id 数据库没有 FK,因此 Account.BRANCH 列可以具有 Branch 表中未显示的任何值。

根据@NotFound(action = NotFoundAction.IGNORE)相关表中是否存在值,Hibernate 将加载该属性的空值。

如果两个帐户的 X 和 Y 列相同(这很好),但 BRANCH 不同并且未出现在 Branch 表中,hibernate 将为两个帐户加载null,并且嵌入式 Id 将相等。

因此,两个 CollectionKey 对象将是相等的,并且对于不同的帐户将具有相同的 hashCode。

result = {CollectionKey@34809} "CollectionKey[Account.loans#Account@43deab74]"
 role = "Account.loans"
 key = {Account@26451} 
 keyType = {EmbeddedComponentType@21355} 
 factory = {SessionFactoryImpl@21356} 
 hashCode = 1187125168
 entityMode = {EntityMode@17415} "pojo"

result = {CollectionKey@35653} "CollectionKey[Account.loans#Account@33470aa]"
 role = "Account.loans"
 key = {Account@35225} 
 keyType = {EmbeddedComponentType@21355} 
 factory = {SessionFactoryImpl@21356} 
 hashCode = 1187125168
 entityMode = {EntityMode@17415} "pojo"
Run Code Online (Sandbox Code Playgroud)

因此,Hibernate 将为两个实体加载相同的 PecientSet。


Die*_*o87 5

在线阅读引起此错误的原因也可能是休眠错误,因为似乎可以解决该问题的方法是,将以下内容放入:

session.clear()
Run Code Online (Sandbox Code Playgroud)

您必须在获取数据之后,提交和关闭之前进行清除,请参见示例:

//getting data
SrReq sr = (SrReq) crit.uniqueResult();
SrSalesDetailDTO dt=SrSalesDetailMapper.INSTANCE.map(sr);
//CLEAR            
session.clear();
//close session
session.getTransaction().commit();
session.close();
return dt;
Run Code Online (Sandbox Code Playgroud)

我使用此解决方案选择数据库,进行更新或插入,但我不知道此解决方案是否可以工作或会导致问题。

我的问题等于100%:http//www.progtown.com/topic128073-hibernate-many-to-many-on-two-tables.html