Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA One-to-One relation creates a non unique foreign key

I have the follwoing entity:

@Entity
public class A {

  // id, etc..

  @OneToOne
  private B b;
}

The table a already exists and when i add the new field b to it, hibernate executes the following:

alter table a add column b_id int8
alter table a add constraint FKg76mxqt8whi8t8p4i7el95910 foreign key (b_id) references b

As you see, the foreign key column b_id is not unique. Why is that the case? Doesn´t the One-to-One relation imply that the foreign key has to be unique? That´s also what i found in the JPA specification for unidirectional One-to-One relatoins:

[...] The foreign key column has the same type as the primary key of table B and there is a unique key constraint on it.

To make it work i have to explicitally add the @JoinColumn(unique=true) annotation to the field. Why do i have to do that explicitally?

like image 445
M.Dietz Avatar asked Oct 16 '22 05:10

M.Dietz


1 Answers

Bi-directional @OneToOne

In order to create a unique constraint you have to create a complete bi-directional OneToOne relation.

This means you have to add @OneToOne annotation on the Parent (Owning) entity, and add @OneToOne(mappedBy="...") on the Child entity.

This will create a unique constraint on your id column.

Otherwise, you're modeling two different relations instead of one bi-directional relation; because of that nothing is stopping the current model from having two Childs pointing to the same Parent.

The official JavaDoc for @OneToOne annotation has more information on additional parameters and advice on bi-directional relation.

UPD: Link to hibernate specification on how it is handling of @OneToOne relation:

  1. When using a bidirectional @OneToOne association, Hibernate enforces the unique constraint upon fetching the child-side.
  2. A unidirectional association follows the relational database foreign key semantics, the client-side owning the relationship.

In your case

This means that on your B entity model you should add a field with your A entity and annotate it with @OneToOne(mappedBy="b") to make your relation bi-direactional and complete, restricting access to single Parent and creating a unique constraint.

like image 62
Markiian Benovskyi Avatar answered Nov 02 '22 08:11

Markiian Benovskyi