9

Foreign Key Constraint Problem for One-to-Many Unidirectional Relationship

 2 years ago
source link: https://www.codesd.com/item/foreign-key-constraint-problem-for-one-to-many-unidirectional-relationship.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Foreign Key Constraint Problem for One-to-Many Unidirectional Relationship

advertisements

I have Employee (parent) and Emp_Contacts (child). Only Employee 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;

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

My Emp_Contacts is as follows:

@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 table has not null FK constraint for emp_contacts table on emp_id.

  1. If I remove above constraint then persist(employee) 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 https://forum.hibernate.org/viewtopic.php?f=1&t=995514

But if I put nullable in Employee:

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


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;




About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK