【发布时间】:2016-10-07 00:34:42
【问题描述】:
我很难理解这种 JPA 行为,在我看来它似乎不符合规范。 我有 2 个基本实体:
public class User {
@Id
@Column(name = "id", unique = true, nullable = false, length = 36)
@Access(AccessType.PROPERTY)
private ID id;
@OrderBy("sequence ASC")
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = { CascadeType.REMOVE })
private final Set<UserProfile> userprofiles = new HashSet<UserProfile>(0);
//Ommiting rest of fields since they aren't relevant
}
public class UserProfile {
@Id
@Column(name = "id", unique = true, nullable = false, length = 36)
@Access(AccessType.PROPERTY)
private ID id;
@NotNull
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "userID", nullable = false, foreignKey = @ForeignKey(name = "FK_UserProfile_User"))
private User user;
//Ommiting rest of fields since they aren't relevant
}
如您所见,我只将级联设置为 REMOVE,如果我根本没有设置级联,行为将是相同的。
现在如果我打电话:
User user = new User();
user.setId(UUIDGenerator.generateId());
UserProfile userProfile = new UserProfile();
userProfile.setId(UUIDGenerator.generateId());
userProfile.setUser(user);
user.getUserProfiles().add(userProfile);
em.merge(user);
合并会抛出异常。
我看到 Hibernate 正在对 UserProfile 表执行 SQL 查询: 选择 userprofil0_.userProfileID 作为 userProf1_4_0_,userprofil0_.profileID 作为 profileI3_4_0_,userprofil0_.sequence 作为 sequence2_4_0_,userprofil0_.userID 作为 userID4_4_0_ from UserProfile userprofil0_ where userprofil0_.userProfileID=?
然后会抛出异常 org.springframework.orm.jpa.JpaObjectRetrievalFailureException:无法找到 com.mytest.domain.UserProfile,id 为 6aaab891-872d-41e6-8362-314601324847;
为什么还要调用这个查询?
由于我没有在 userprofiles 中将级联类型设置为 MERGE,我的期望是 JPA/Hibernate 会简单地忽略 userprofiles 集中的实体并仅插入/更新用户记录,这不违反 JPA 规范?
如果我将 cascadetype 更改为 MERGE,事情将按预期工作,并且 User 和 UserProfile 都将添加到数据库中,所以没有问题。让我感到困惑的是,为什么 Hibernate 会查询数据库并错误地指出一个根本不应该合并的实体,因为我没有将它设置为级联。
这更像是我遇到的一个学术场景,当然我可以简单地清除用户配置文件集并且事情会起作用,但我试图理解为什么会发生上述行为,因为我可能错过了一些关键部分有关合并如何工作的信息。无论是否设置了级联类型,它似乎总是会尝试将所有实体附加到会话。
【问题讨论】: