17


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.

7
  • 3
    If you want to fight hibernate... go ahead and use composite keys. If you want a much easier life, ensure each table has a single primary key column. Trust me, it's not worth the fight... it's a battle which will cost you many hours in the future Commented Sep 17, 2015 at 8:13
  • What do you mean by "part of primary key"? Composite primary keys in Hibernate are quite simple, but you shouldn't try to complicate that by trying to use only a part of it. Basicly you need a composite key class. There is an answer here with all basic details: stackoverflow.com/questions/3585034/… Commented Sep 17, 2015 at 8:15
  • There's a fairly thorough answer here: stackoverflow.com/a/3588400/3166303 Commented Sep 17, 2015 at 8:16
  • For one-to-many mappings you don't require a composite key. It is so so easier to manage this situation without using composite key. Commented Sep 17, 2015 at 8:18
  • @LanceJava In this case I need to use composite keys because of readability. Commented Sep 17, 2015 at 8:20

2 Answers 2

16

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;
}
Sign up to request clarification or add additional context in comments.

6 Comments

To get above code work you also need to implement Serializable for all above classes
I tried this way and I'm getting Unable to find column reference in the @MapsId mapping: c. Any idea?. TIA
Is it a runtime or compile error? Could you post your code somewhere so that I can have a look at it?
Is it possible to have MapsId for two attrributes? For example, if there was an attribute 'd' which is also part of both keys (same as b)?
Unfortunately it is not possible to have multiple ´@MapsId´ annotations on the same attribute. But I managed to solve it for my use case by using ´@JoinFormula´ instead of ´@JoinColumn´ for the columns that are used in Primary Key as well as Foreign Key.
|
-1

Jagger's second solution that is my first reaction, with @EmbededId and @MapsId. The following is another way based on his second solution but without using @MapsId. `

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

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

1 Comment

This won't work and ends with an exception org.hibernate.AnnotationException: Mixing insertable and non insertable columns in a property is not allowed There is a Hibernate bug for it .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.