当我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 隔离这个问题,但它对我没有帮助.

推荐答案

TeamEntity类的方法addUser()中,您正在将新的UserTeamEntity实例添加到usersuserEntity.getUserTeams()持久集中.Hibert将其记录为两个新实体,当您try 持久化TeamEntity实体时,它检测到必须持久化两个具有相同主密钥的实体,然后引发异常.

当您持久化实体时,您必须以一种方式调整您的代码,使UserTeamEntity不在两个集中.

Java相关问答推荐

Javascript在边界中心调整ImageView大小

Spark忽略Iceberg Nessie目录

按属性值从流中筛选出重复项

在JDK 1.8源代码中,为什么使用A-B 0来确定哪个更大,而不是A B?

使用用户引入的参数生成人员数组

WebSockets和Spring Boot安全性出现错误401

Spring安全令牌刷新和JWT签名与本地计算的签名不匹配

由于在生成器模式中使用泛型,lambda表达式中的返回类型错误

将JSON字符串转换为Java类

在Oracle JDBC连接中,连接失效和身份验证失效是什么意思?

try 使用预准备语句占位符获取信息时出现Try-With-Resources错误

项目react 堆中doOnComplete()和Subscribe()的第三个参数之间的差异

在使用具有不同成本的谓词调用allMatch之前对Java流进行排序会带来什么好处吗?

如何在运行docker的应用程序中获取指定的配置文件

使IntelliJ在导入时优先 Select 一个类或将另一个标记为错误

我的代码是线程安全的吗?[Java、CAS、转账]

未调用OnBackPressedCallback-Activitiy立即终止

AspectJ编织外部依赖代码,重新打包jar并强制依赖用户使用它

javax.crypto-密码对象-提供者服务是如何工作的?

原始和参数化之间的差异调用orElseGet时可选(供应商)