user2869612 user2869612 - 1 year ago 70
Java Question

Foreign key constraint issue for One-to-Many unidirectional relation

I have

(parent) and
(child). Only
class has unidirectional mapping.

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;

public class Employee {

@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...

is as follows:

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

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

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


DB table has not null FK constraint for
table on

  1. If I remove above constraint then
    will persists employee and corresponding emp_contacts.

  2. With FK constraint I get below error:

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

I searched on internet and found this link

But if I put nullable in

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

my server does not even start, I get below error:

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

What am I doing wrong ?

Answer Source

Employee is the association owning side (because it's the only side). That way foreign key is always updated separately from inserting the associated Emp_Contacts instances, so it must be nullable.

The recommended solution is to make the association bidirectional and make the many side the owner of the association:

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;

This way the foreign key can be not-nullable and you avoid the costs of an extra statement to update the foreign key because the foreign key value is set when inserting Emp_Contacts.

Also, you will always have the associated employee id in the Emp_Contacts instance (what seems to be your intention). You don't have to load the employee from the database in order to access its id because the association can be declared lazy (as in the example above) and Hibernate will generate a proxy containing only the id. See this answer for more information.

Another benefit is that you can navigate the association from both sides when needed (useful also in HQL/JPQL queries).

If you nevertheless want to use your original solution (unidirectional association with only plain foreign key value on the many side), then make the join column nullable and make the emp_id property insertable = false, updatable = false, because Hibernate will automatically update the mapped foreign key column when maintaining the association on the Employee side:

@Column(name = "emp_id, insertable = false, updatable = false")
private long emp_id;
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download