添加关系时,具有额外列的 Hibernate 多对多关系返回 NonUniqueObjectException

问题描述 投票:0回答:1

在尝试更新用户和团队之间的多对多关系时遇到错误。我几乎关注了 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 在持久化之前创建了自己的对象实例!.
  • 我还确保我所做的事情与我关注的博客中没有太大不同。
  • 上面的代码也是来自一个更大项目的最小示例,以便我可以尝试隔离问题,但这对我没有帮助。
java spring-boot hibernate
1个回答
0
投票

addUser()
类的方法
TeamEntity
中,您将在
UserTeamEntity
users
持久集中添加新的
userEntity.getUserTeams()
实例。 Hibernate 将其记录为两个新实体,当您尝试持久化
TeamEntity
实体时,它检测到它必须持久化具有相同主键的两个实体,然后引发异常。

您必须以某种方式调整代码,以便在持久化实体时

UserTeamEntity
不在这两个集合中。

© www.soinside.com 2019 - 2024. All rights reserved.