在尝试更新用户和团队之间的多对多关系时遇到错误。我几乎关注了 Vlad 的博客,解释了如何实现该模型。我正在使用最新版本的 Springboot (3.2.4),因此也是最新版本的 Hibernate 和 Java 17 之一。我急切地加载了所有内容,因为这不是我问题的重点。这是我的实体(不是完整的类,以使其更具可读性):
用户实体:
public class UserEntity {
public UserEntity(String loginName) {
this.loginName = loginName;
}
@Id
@Getter
@Setter
@Column(name = "login_name")
private String loginName;
@OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.EAGER
)
private Set<UserTeamEntity> teams = new HashSet<>();
public void addTeam(TeamEntity team, boolean isTeamLeader, boolean isPrimaryTeam) {
Optional<UserTeamEntity> optionalUserTeam = teams.stream().filter(userTeamEntity -> userTeamEntity.getTeam().equals(team))
.findFirst();
if (optionalUserTeam.isPresent()) {
optionalUserTeam.get().setTeamLeader(isTeamLeader);
optionalUserTeam.get().setUserPrimaryTeam(isPrimaryTeam);
} else {
UserTeamEntity userTeamEntity = new UserTeamEntity(this, team, isTeamLeader, isPrimaryTeam);
teams.add(userTeamEntity);
team.getUserTeams().add(userTeamEntity);
}
}
Set<UserTeamEntity> getUserTeams() {
return teams;
}
团队实体
public class TeamEntity {
public TeamEntity(String displayName) {
this.id = null;
this.displayName = displayName;
this.users = new HashSet<>();
}
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
@GenericGenerator(name = "native")
private Long id;
@Column(name = "display_name")
private String displayName;
@OneToMany(
mappedBy = "team",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.EAGER
)
private Set<UserTeamEntity> users = new HashSet<>();
public void addUser(UserEntity userEntity, boolean isPrimaryTeam, boolean isLeader) {
Optional<UserTeamEntity> optionalUserTeam = users.stream().filter(userTeamEntity -> userTeamEntity.getUser().equals(userEntity))
.findFirst();
if (optionalUserTeam.isPresent()) {
optionalUserTeam.get().setTeamLeader(isLeader);
optionalUserTeam.get().setUserPrimaryTeam(isPrimaryTeam);
} else {
UserTeamEntity userTeamEntity = new UserTeamEntity(userEntity, this, false, false);
users.add(userTeamEntity);
userEntity.getUserTeams().add(userTeamEntity);
}
}
Set<UserTeamEntity> getUserTeams() {
return users;
}
}
用户团队实体
public class UserTeamEntity {
@EmbeddedId
private UserTeamId id;
@ManyToOne(fetch = FetchType.EAGER)
@MapsId("userLoginName")
private UserEntity user;
@ManyToOne(fetch = FetchType.EAGER)
@MapsId("teamId")
private TeamEntity team;
@Column(name = "is_team_leader")
@Convert(converter = YesNoConverter.class)
private boolean isTeamLeader = false;
@Column(name = "is_user_primary_team")
@Convert(converter = YesNoConverter.class)
private boolean isUserPrimaryTeam = false;
public UserTeamEntity(UserEntity user, TeamEntity team, boolean isTeamLeader, boolean isUserPrimaryTeam) {
this.id = new UserTeamId(user.getLoginName(), team.getId());
this.user = user;
this.team = team;
this.isTeamLeader = isTeamLeader;
this.isUserPrimaryTeam = isUserPrimaryTeam;
}
}
在集成测试中将用户添加到团队(或相反)并更新团队(何时部分中的第四步)时,我收到错误
Caused by: org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.example.UserTeamEntity#com.example.UserTeamId]
@Test
void updateTeamService() {
// GIVEN
TeamEntity team = createTeam(TEAM_DISPLAY_NAME);
createUser(USER_LOGIN_NAME);
// WHEN
TeamEntity teamToUpdate = userTeamService.findById(team.getId());
UserEntity userToAdd = userTeamService.findById(USER_LOGIN_NAME);
teamToUpdate.addUser(userToAdd, false, false);
userTeamService.updateTeam(teamToUpdate);
// THEN
TeamEntity updatedEntity = userTeamService.findById(team.getId());
assertEquals(1, updatedEntity.getAllUsers().size());
assertTrue(updatedEntity.getAllUsers().stream().anyMatch(user -> USER_LOGIN_NAME.equalsIgnoreCase(user.getLoginName())));
}
对于完整的可重现示例,您可以查看 我的 github 存储库
之一任何帮助将不胜感激,因为我真的很困惑为什么这不起作用。
到目前为止我尝试或调查过的内容:
UserTeamId
具有与会话关联的不同对象。 似乎 hibernate 在持久化之前创建了自己的对象实例!.在
addUser()
类的方法 TeamEntity
中,您将在 UserTeamEntity
和 users
持久集中添加新的 userEntity.getUserTeams()
实例。 Hibernate 将其记录为两个新实体,当您尝试持久化 TeamEntity
实体时,它检测到它必须持久化具有相同主键的两个实体,然后引发异常。
您必须以某种方式调整代码,以便在持久化实体时
UserTeamEntity
不在这两个集合中。