【问题标题】:one-way one-to-many throws Hibernate Cannot add or update a child row: a foreign key constraint fails单向一对多抛出休眠无法添加或更新子行:外键约束失败
【发布时间】:2018-06-01 21:06:07
【问题描述】:

我有一个应用程序可以教用户如何玩各种纸牌游戏。持久化的数据模型由一个TrainingSession 组成,它与Hands 具有单向一对多关系。

[EDIT] 澄清一下,HandTrainingSession 的上下文之外不存在(即当TrainingSession 存在时它们被创建/销毁)。遵循数据驱动设计的原则,TrainingSession 被视为聚合根,因此使用单个 spring-data CrudRepository(即,没有为 Hand 创建存储库)

当我尝试使用 CrudRepository 保存 TrainingSession 时,我得到:com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: 无法添加或更新子行:外键约束失败 (blackjack.hand , 约束 FKrpuxac6b80xc7rc98vt1euc3n 外键 (id) 引用 training_session (tsid))

我的问题是通过 CrudRepository 实例的“save(trainingSession)”操作。我不明白为什么错误消息指出FOREIGN KEY (id) REFERENCES training_session (tsid))。这似乎是问题的原因,但我无法弄清楚为什么会这样或如何解决它。这种关系是单向的,Hand 类中没有任何内容涉及 TrainingSession。

代码,减去所有的 getter 和 setter,是:

@Entity
public class TrainingSession {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer tsid;
private String strategy;

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="id")
private List<Hand> hands;

private int userId;

protected TrainingSession() {
}

public TrainingSession(int userId, Strategy strategy, List<Hand> hands) {
    this.strategy = strategy.getClass().getSimpleName();
    this.hands = hands;
    this.userId = userId;
}

Hand

@Entity // This tells Hibernate to make a table out of this class
public class Hand {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private int p1;
private String p1s;
private int p2;
private String p2s;
private int d1;
private String d1s;
private int trials;
private int score;

public Hand() {
}

【问题讨论】:

    标签: spring hibernate jpa foreign-keys spring-data


    【解决方案1】:

    您需要先保存 TrainingSession 和 Hand 对象,然后再保存将手对象添加到 TrainingSession。

    TrainingSession ts1 = new TrainingSession();
    trainingSessionManager.save(ts1);
    
    Hand hand1 = new Hand();
    handManager.save(hand1);
    
    Hand hand2 = new Hand();
    handManager.save(hand2);
    
    ts1.gethands().add(hand1);
    ts1.gethands().add(hand2)
    
    trainingSessionManager.save(ts1);
    

    如果您检查您的数据库,您会发现 3 个表 TrainingSession, Hand and TrainingSession_HandTrainingSession_Hand 表引用了 TrainingSession 和 Hand 两者。因此,您需要在保存关系之前保存 TrainingSession 和 hand。

    【讨论】:

    • 我从您的回复中对handManagertrainingSessionManager 的引用中假设您将其视为Hibernate/JPA 问题,但它实际上是Spring 数据问题。注意CrudRespository 实例的使用。这在我的问题中并不清楚,因此我对其进行了编辑以澄清问题。
    【解决方案2】:

    发现问题。我假设当 spring-data 设置数据库表时,它能够找出并设置单向一对多关系。显然情况并非如此。当我将关系配置为双向时,一切似乎都正常。

    为了解决问题,我:

    • TrainingSession 中删除了手的 @joincolumn 注释
    • Hands 中,我添加了一个带有@ManyToOne 注释的TrainingSession 字段:

      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "tsid", nullable = false)
      @OnDelete(action = OnDeleteAction.CASCADE)
      private TrainingSession tsession;
      
    • 我还在 Hand 类中添加了 tsession 的 getter/setter

    我现在可以只使用TrainingSessionRepository 来保存整个聚合构造。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-04
      相关资源
      最近更新 更多