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