如何正确映射@OneToMany 和@ManyToOne 关系,以便我可以保存和更新@OneToMany 端(有或没有@ManyToOne 端)

Posted

技术标签:

【中文标题】如何正确映射@OneToMany 和@ManyToOne 关系,以便我可以保存和更新@OneToMany 端(有或没有@ManyToOne 端)【英文标题】:How do I map an @OneToMany and @ManyToOne relationship properly so that I can save and update the @OneToMany side with or without the @ManyToOne side 【发布时间】:2020-11-03 01:05:56 【问题描述】:

我有一个带有 Angular 前端和 Spring 后端的应用程序。这里有问题的两个类是(后端):

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "tournament_games")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class TournamentGame 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "code", foreignKey = @ForeignKey(name = "code_fk"))
    private TournamentCode code;

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "type", foreignKey = @ForeignKey(name = "game_type_fk"))
    private GameType type;

    @Column(name = "home_score")
    private int home_score;

    @Column(name = "away_score")
    private int away_score;

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "result_type", foreignKey = @ForeignKey(name = "result_type_fk"))
    private ResultType result_type;

    @Column(name = "status")
    private boolean status;

    @Column(name = "round")
    private int round;

    @Column(name = "locked")
    private boolean locked;

    @OneToMany(mappedBy = "game", fetch = FetchType.EAGER)
    private List<TournamentGamesPlayers> players = new ArrayList<>();

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "tournament_games_players")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "game")
public class TournamentGamesPlayers implements Serializable 

    private static final long serialVersionUID = 1L;

    @Id
    @ManyToOne
    @JoinColumn(name = "tournament_game_id")
    private TournamentGame game;

    @Id
    @ManyToOne
    @JoinColumn(name = "playerid")
    private Player player;

    @Column(name = "home")
    private boolean home;

当我保存和/或更新 TournamentGame 对象时,我需要帮助弄清楚如何持久化 List&lt;TournamentGamesPlayers&gt;。我生成了 45 个游戏。前 30 场比赛都有已知玩家,所以我在保存之前设置了它们。最后 15 个没有 TournamentGamesPlayers 连接表的条目,因为我需要稍后添加它们。

当我最初生成游戏时,我能够在@OneToMany 端使用CascadeType.ALL 获得一些结果,但是当我尝试更新具有看似无限递归/堆栈溢出的游戏时它失败了。

如果我省略任何级联类型,则会生成游戏端,但不会输入连接表 @ManyToOne 端。

【问题讨论】:

你能澄清你的问题吗? 我想我的问题是处理上面定义的这种关系的最佳方法是什么。我有一个包含 TournamentGamesPlayers 列表的 TournamentGame。 TournamentGamesPlayers 映射到一个包含 TournamentGame 和 Player 的复合键的连接表,并添加了一个附加字段。现在的问题似乎是我可以更新一个 TournamentGame,只要它在连接表中有现有的 TournamentGamesPlayers 条目......但是如果我有一个在连接表中没有此类条目的游戏,并希望通过将新 List 添加到属性中来添加它们,并保存它,我不能 同时移除级联允许我更新现有游戏而不会出现堆栈溢出。但是,它似乎没有在连接表中保存新条目(又名新的 TournamentGamesPlayers)......它引发了一个错误,无法找到具有 id 的 TournamentGamesPlayers......我生成了 45 个游戏。其中30名球员从一开始就为人所知。最后 15 场比赛在连接表中还没有条目。我想稍后通过设置 List 并保存 TournamentGame 来保留这些内容。不知道该怎么做。 事实上,现在我已经删除了级联,我最初的 30 场比赛不再将条目保存到我的联接表中。我刚刚举办了一场新的锦标赛。 45 款游戏以其默认值添加到数据库中。但是我分配给前 30 场比赛的 List 没有得到持久化。 我用一些澄清和更新的代码更新了这个问题。 【参考方案1】:

尝试将 CascadeType.MERGE、CascadeType.ALL “删除父项和孤儿” (JPA CascadeType.ALL does not delete orphans)。

此外,将关系定义为 EAGER 并且不忽略 JSON 属性可能会出现问题。我会将@JsonIgnore 添加到关系的一部分中

【讨论】:

【参考方案2】:

我最终只是将玩家放回游戏桌以让我的生活更轻松。

【讨论】:

以上是关于如何正确映射@OneToMany 和@ManyToOne 关系,以便我可以保存和更新@OneToMany 端(有或没有@ManyToOne 端)的主要内容,如果未能解决你的问题,请参考以下文章

在 Scala Play 框架中映射 OneToMany 不向第二个表插入数据

在 Hibernate OneToMany 映射中

如何使用 HQL 在 OneToMany 映射中查找列的最大值?

如何在 Hibernate 中创建 OneToMany 映射? [复制]

如何在 @OneToMany 关系映射的列上使用 JPA findBy 查询?

Hibernate如何正确删除@OneToMany中的孩子?