当我try 更新用户和团队之间的多对多关系时,我遇到了错误.我几乎关注了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<User团队实体> teams = new HashSet<>();
public void addTeam(团队实体 team, boolean isTeamLeader, boolean isPrimaryTeam) {
Optional<User团队实体> optionalUserTeam = teams.stream().filter(user团队实体 -> user团队实体.getTeam().equals(team))
.findFirst();
if (optionalUserTeam.isPresent()) {
optionalUserTeam.get().setTeamLeader(isTeamLeader);
optionalUserTeam.get().setUserPrimaryTeam(isPrimaryTeam);
} else {
User团队实体 user团队实体 = new User团队实体(this, team, isTeamLeader, isPrimaryTeam);
teams.add(user团队实体);
team.getUserTeams().add(user团队实体);
}
}
Set<User团队实体> getUserTeams() {
return teams;
}
团队实体
public class 团队实体 {
public 团队实体(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<User团队实体> users = new HashSet<>();
public void addUser(UserEntity userEntity, boolean isPrimaryTeam, boolean isLeader) {
Optional<User团队实体> optionalUserTeam = users.stream().filter(user团队实体 -> user团队实体.getUser().equals(userEntity))
.findFirst();
if (optionalUserTeam.isPresent()) {
optionalUserTeam.get().setTeamLeader(isLeader);
optionalUserTeam.get().setUserPrimaryTeam(isPrimaryTeam);
} else {
User团队实体 user团队实体 = new User团队实体(userEntity, this, false, false);
users.add(user团队实体);
userEntity.getUserTeams().add(user团队实体);
}
}
Set<User团队实体> getUserTeams() {
return users;
}
}
User团队实体
public class User团队实体 {
@EmbeddedId
private UserTeamId id;
@ManyToOne(fetch = FetchType.EAGER)
@MapsId("userLoginName")
private UserEntity user;
@ManyToOne(fetch = FetchType.EAGER)
@MapsId("teamId")
private 团队实体 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 User团队实体(UserEntity user, 团队实体 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;
}
}
When adding a user to the team (or the other way around) in an integration test and updating the team (4th step in the WHEN part), I get the error Caused by: org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.example.User团队实体#com.example.UserTeamId]
@Test
void updateTeamService() {
// GIVEN
团队实体 team = createTeam(TEAM_DISPLAY_NAME);
createUser(USER_LOGIN_NAME);
// WHEN
团队实体 teamToUpdate = userTeamService.findById(team.getId());
UserEntity userToAdd = userTeamService.findById(USER_LOGIN_NAME);
teamToUpdate.addUser(userToAdd, false, false);
userTeamService.updateTeam(teamToUpdate);
// THEN
团队实体 updatedEntity = userTeamService.findById(team.getId());
assertEquals(1, updatedEntity.getAllUsers().size());
assertTrue(updatedEntity.getAllUsers().stream().anyMatch(user -> USER_LOGIN_NAME.equalsIgnoreCase(user.getLoginName())));
}
对于完整的可复制示例,您可以查看my github repository个中的一个
我们将不胜感激,因为我真的很困惑为什么这不起作用.
到目前为止我已经try 或调查了什么:
- 我试图深入研究hibiter并了解错误的起源,但我根本不明白为什么
UserTeamId
具有与会话关联的不同对象.It seems like hibernate is creating its own instance of the object before persisting it!. - 我还确保我所做的事情不会与我关注的博客有很大不同.
- 上面的代码也是来自一个更大项目的最小示例,这样我就可以try 隔离这个问题,但它对我没有帮助.