一对多单向关系的外键约束问题

use*_*612 7 java mysql hibernate foreign-keys spring-mvc

我有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...
Run Code Online (Sandbox Code Playgroud)

我的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;

....
Run Code Online (Sandbox Code Playgroud)

对于emp_contacts表,DB表没有null FK约束emp_id.

  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
Run Code Online (Sandbox Code Playgroud)

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

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

我究竟做错了什么 ?

Dra*_*vic 7

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;
}
Run Code Online (Sandbox Code Playgroud)

这样,外键可以不为空,并且您可以避免额外语句更新外键的成本,因为插入时设置了外键值Emp_Contacts.

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

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

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

@Column(name = "emp_id, insertable = false, updatable = false")
private long emp_id;
Run Code Online (Sandbox Code Playgroud)