我有一个很好的例子来重现这样的问题。也许我的经验有一天会帮助某人。
简洁版本
检查您的容器的@Embedded Id 是否没有可能的冲突。
长版
当 Hibernate 实例化集合包装器时,它会在内部 Map 中通过 CollectionKey 搜索已经实例化的集合。
对于具有@Embedded id 的实体,CollectionKey 包装 EmbeddedComponentType 并使用@Embedded Id 属性进行相等性检查和 hashCode 计算。
因此,如果您有两个具有相同 @Embedded Ids 的实体,Hibernate 将通过第一个键实例化并放置新集合,并为第二个键找到相同的集合。因此,具有相同 @Embedded Id 的两个实体将填充相同的集合。
例子
假设您的 Account 实体有一组惰性贷款。并且 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;
...
}
然后假设 Account 具有由@Embedded Id 映射的附加属性,但与其他实体分支有关系。
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "BRANCH")
@MapsId("accountId.branchId")
@NotFound(action = NotFoundAction.IGNORE)//Look at this!
private Branch branch;
您可能没有帐户到早午餐关系 id DB 的 FK,因此 Account.BRANCH 列可以具有分支表中未显示的任何值。
根据@NotFound(action = NotFoundAction.IGNORE)
相关表中是否存在值,Hibernate 将为该属性加载空值。
如果两个 Account 的 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"
因此,Hibernate 将为两个实体加载相同的 PesistentSet。