JPA+Hibernate - 从 @OneToMany 关系重新连接实体

发布于 2024-08-22 10:26:39 字数 1119 浏览 4 评论 0原文

考虑以下简单示例: 一支球队有多名球员,一名球员可能只属于一支球队。

@Entity
public class Team {

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "team")
    @Cascade({  org.hibernate.annotations.CascadeType.ALL,
                org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
    private Set<Player> player = new HashSet<Player>();

}

@Entity
public class Player {

    @NotNull
    @ManyToOne(targetEntity = Team.class)
    @JoinColumn(name = "team_id")
    private Team team;

}

我想要实现的是将A队的所有球员转移到B队,然后删除A队。我对 A 队的玩家进行循环,并将他们的团队设置为 B 队(此处:“this”):

Iterator<Player> iterator = teamA.getPlayer().iterator();
while(iterator.hasNext()){
 Player player = iterator.next();
 player.setTeam(this);
    player.merge();
}
teamA.remove();

刷新是在那之后完成的(自动刷新),但我也尝试在 teamA.remove() 之前刷新。这段代码运行时没有错误,但之后由于级联配置,A 队的球员被从我的数据源中删除,因为 teamA.remove() 导致 A 队的所有球员被删除。

我想知道为什么他们仍然与A 队,因为我也尝试(并在调试器中检查)从集合中删除所有玩家,所以当调用 teamA.remove() 时,集合为空。在这些情况下抛出的异常要么指出“传递到持久化的已删除实体”,要么是“传递到持久化的分离实体”。当然,如果我创建一个新的瞬态播放器,复制所有属性和 .persist(),它确实有效。

如何通过简单地“重新链接”关系来做到这一点?

Consider the following simple example:
One team has many players and a player may only belong to one team.

@Entity
public class Team {

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "team")
    @Cascade({  org.hibernate.annotations.CascadeType.ALL,
                org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
    private Set<Player> player = new HashSet<Player>();

}

@Entity
public class Player {

    @NotNull
    @ManyToOne(targetEntity = Team.class)
    @JoinColumn(name = "team_id")
    private Team team;

}

What I want to achive is moving all players of team A to team B and delete team A afterwards. I do a loop over the players from team A and set their team to team B (here: "this"):

Iterator<Player> iterator = teamA.getPlayer().iterator();
while(iterator.hasNext()){
 Player player = iterator.next();
 player.setTeam(this);
    player.merge();
}
teamA.remove();

The flush is done after that (autoflush), but I also tried to flush before teamA.remove(). This code runs without an error, but afterwards the players from team A are removed from my datasource due to the cascade configuration, as teamA.remove() leads to the removal of all players from team A.

I wonder why they are still associated with team A, because I also tried (and checked in the debugger) to remove all players from the Set, so when teamA.remove() is called, the set is empty. The exceptions thrown in those cases either stated "deleted entity passed to persist" or "detached entity passed to persist". It does work of course, if I create a new transient player, copy all properties and .persist().

How to do this by simply "relinking" the relationship?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

是伱的 2024-08-29 10:26:39

你有没有尝试过:

team2.setPlayers(team1.getPlayers();
team1.setPlayers(null);
for (Player player : team2.getPlayers() {
   player.setTeam(team2);
}

Have you tried:

team2.setPlayers(team1.getPlayers();
team1.setPlayers(null);
for (Player player : team2.getPlayers() {
   player.setTeam(team2);
}
十秒萌定你 2024-08-29 10:26:39

我认为你必须在调用 teamA 上的删除之前清空集合。但你说你试过了?

新团队是一个持久的实体吗?

I think you have to empty the set before calling remove on teamA. But you said you tried that?

Is the new team a persisted entiy?

萌梦深 2024-08-29 10:26:39

我认为罪魁祸首是 DELETE_ORPHAN。来自注释参考:

DELETE_ORPHAN 仅适用于@OneToMany 关联,并指示delete()/remove() 操作应应用于从关联中删除的任何子对象。换句话说,如果持久父级取消引用子级并且使用 DELETE_ORPHAN,则“孤立”子级将被删除。

但这不是您想要的,因为您正在“重新调整”播放器。

I think the culprit is the DELETE_ORPHAN. From the Annotations reference:

DELETE_ORPHAN applies only to @OneToMany associations, and indicates that the delete()/remove() operation should be applied to any child object that is removed from the association. In other words, if a child is dereferenced by a persistent parent and if DELETE_ORPHAN is used, the "orphaned" child is deleted.

But this isn't what you want since you're "reparenting" the Player.

属性 2024-08-29 10:26:39

我认为当你改变队员的队伍后,你应该调用flush(),然后在teamA上调用refresh(),然后在teamA上调用remove()。

I think that after you change the team of the players, you should call flush(), then call refresh() on teamA and then call remove() on teamA.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文