Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate foreign key with a part of composite primary key


I have to work with Hibernate and I am not very sure how to solve this problem, I have 2 tables with a 1..n relationship like this:

-------
TABLE_A
-------
col_b (pk)
col_c (pk)
[other fields]

-------
TABLE_B
-------
col_a (pk)
col_b (pk) (fk TABLE_A.col_b)
col_c (fk TABLE_A.col_c)
[other fields]

How can I manage this with Hibernate?

I do not have any idea how to declare a foreign key that would contain a part of primary key.

My database schema is generated from the Hibernate model.

like image 981
Jagger Avatar asked Sep 17 '15 08:09

Jagger


People also ask

Can a foreign key be part of a composite primary key?

This is not possible. The foreign key can not refer to part of composite primary key of other table. Because it is supposed to be one-to-one relationship and if you refer just part of primary-key, there might be more than one parent record available, which is neither allowed nor possible.

Can a key be primary and foreign at the same time?

A table can have only one Primary Key. A table can have any number of Foreign Keys. The primary key is unique and Not Null. A foreign key can contain duplicate values also.

How do you make a foreign key a primary key in Hibernate?

You can use JPA's @MapsId annotation to tell Hibernate that it shall use the foreign key of an associated entity as the primary key. Let's take a look at a simple example. Each Book has a Manuscript, and each Manuscript belongs to 1 Book. The foreign key of the Book is also the primary key of the Manuscript.


1 Answers

I have found two solutions to this problem.

The first one is rather a workaround and is not so neat as the second one.

Define the primary key of the B entity as composite key containing col_a, col_b, and col_c and what was supposed to be the primary key in the first place, define as unique constraint. The disadvantage is that the column col_c is not really conceptually a part of primary key.

@Entity
class A {
  @Id
  private int b;
  @Id
  private int c;
}

@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = { "a", "b" }) })
class B {
  @Id
  private int a;

  @Id
  @ManyToOne(optional = false)
  @JoinColumns(value = {
          @JoinColumn(name = "b", referencedColumnName = "b"),
          @JoinColumn(name = "c", referencedColumnName = "c") })
  private A entityA;
}

The second uses @EmbeddedId and @MapsId annotations and does exactly what I wanted to be done at the very beginning.

@Entity
class A {
  @Id
  private int b;
  @Id
  private int c;
}

@Embeddable
class BKey {
  private int a;
  private int b;
}

@Entity
class B {
  @EmbeddedId
  private BKey primaryKey;

  @MapsId("b")
  @ManyToOne(optional = false)
  @JoinColumns(value = {
          @JoinColumn(name = "b", referencedColumnName = "b"),
          @JoinColumn(name = "c", referencedColumnName = "c") })
  private A entityA;
}
like image 98
Jagger Avatar answered Sep 21 '22 11:09

Jagger