【问题标题】:Foreign key constraint issue for One-to-Many unidirectional relation一对多单向关系的外键约束问题
【发布时间】:2016-03-30 17:03:19
【问题描述】:

我有Employee(父母)和Emp_Contacts(孩子)。只有Employee 类具有单向映射。

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.NotEmpty;

@Entity
@Table(name="EMPLOYEE")
public class Employee {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private int id;

  @Size(min=3, max=50)
  @Column(name = "NAME", nullable = false)
  private String name;

...

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  @JoinColumn(name = "emp_id")
  private Set<Emp_Contacts> contacts;

...getters and setters...

我的Emp_Contacts如下:

@Entity
@Table(name = "Emp_Contacts")
public class Emp_Contacts implements Serializable {

  private static final long serialVersionUID = 1L;
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private int emp_contact_id;

  @NotNull
  @Column(name = "emp_id")
  private long emp_id;

....

DB 表对emp_contacts 上的emp_id 表没有空FK 约束。

  1. 如果我删除上述约束,那么 persist(employee) 将保留员工和相应的 emp_contacts。
  2. 使用 FK 约束我得到以下错误:

    MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails

我在网上搜索,发现这个链接https://forum.hibernate.org/viewtopic.php?f=1&t=995514

但如果我在Employee 中输入可空值:

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "emp_id", nullable = false)
private Set<Emp_Contacts> contacts

我的服务器甚至没有启动,我收到以下错误:

Repeated column in mapping for entity: com.cynosure.model.Emp_Contacts
column: emp_id (should be mapped with insert="false" update="false")

我做错了什么?

【问题讨论】:

    标签: java mysql hibernate spring-mvc foreign-keys


    【解决方案1】:

    Employee 是关联拥有方(因为它是唯一的一方)。这样,外键总是与插入关联的 Emp_Contacts 实例分开更新,因此它必须可以为空。

    推荐的解决方案是使关联双向,并使多方成为关联的所有者:

    public class Employee {
      @OneToMany(mappedBy = "employee")
      private Set<Emp_Contacts> contacts;
    }
    
    public class Emp_Contacts {
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "emp_id", nullable = false)
      private Employee employee;
    }
    

    通过这种方式,外键可以是不可空的,并且您可以避免额外语句来更新外键的成本,因为在插入 Emp_Contacts 时设置了外键值。

    此外,您将始终在 Emp_Contacts 实例中拥有关联的员工 ID(这似乎是您的意图)。您不必从数据库中加载员工来访问其 id,因为可以将关联声明为惰性(如上例所示),并且 Hibernate 将生成仅包含 id 的代理。请参阅this answer 了解更多信息。

    另一个好处是您可以在需要时从双方导航关联(在 HQL/JPQL 查询中也很有用)。

    如果您仍然想使用您的原始解决方案(单向关联仅与多方面的普通外键值),则将连接列设置为可为空并设置 emp_id 属性 insertable = false, updatable = false,因为 Hibernate 将自动更新在Employee 端维护关联时映射的外键列:

    @Column(name = "emp_id, insertable = false, updatable = false")
    private long emp_id;
    

    【讨论】:

    • 工作就像一个魅力!你让我今天一整天都感觉很好。我还将关联更改为双向。
    • 您是否从子表的实体对象中获取 emp_id?在我的情况下,由于双向一对多映射外键被存储在子表中,但没有反映在实体对象中。你能帮忙吗
    • 我需要它的单向关系。你能帮帮我吗?
    【解决方案2】:
    1. 当 Hibernate 必须删除子值时,它会尝试使外键无效。您不必删除外键上的约束来保持对 Emp_Contacts 的更改。相反,在 JoinColumn 注释上,设置 updatable = false。这告诉 Hibernate 不要更改外键值。
    2. 接下来,在 OneToMany 注释上设置 orphanRemoval = true。您可能会认为 Hibernate 默认 orphanRemoval 为 true,但事实并非如此 :(。我们的团队与这种愚蠢的行为斗争了几天。希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      我不确定这里,但你可以尝试删除

      @NotNull
      @Column(name = "emp_id")
      private long emp_id;
      

      来自Emp_Contacts 类。在我看来,Hibernate 似乎抱怨 emp_id 的重复映射,而您已经在 Employee 中映射了该列。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-12
        • 1970-01-01
        • 2011-05-16
        • 2019-06-20
        • 1970-01-01
        • 2020-03-17
        • 1970-01-01
        • 2013-08-12
        相关资源
        最近更新 更多