Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping an @Embeddable in a separate table

Two tables like:

CREATE TABLE foo (
  id INT PRIMARY KEY,
  x TEXT
);

CREATE TABLE bar (
  foo_id INT REFERENCES foo (id) ON DELETE CASCADE,
  y TEXT,
  z TEXT
);

...can be mapped like so:

@Table(name = "foo")
@SecondaryTable(name = "bar", pkJoinColumns = @PrimaryKeyJoinColumn(name = "foo_id", referencedColumnName = "id"))
class Foo {

  @Id
  int id;

  @Embedded
  @AttributeOverrides({
    @AttributeOverride(name = "y", column = @Column(table = "bar")),
    @AttributeOverride(name = "z", column = @Column(table = "bar"))
  })
  Bar bar;
}

@Embeddable
class Bar {
  String y;
  String z;
}

Is there a less awkward way to do this mapping, using either just standard JPA annotations, or else Hibernate-specific annotations (and without introducing a parent reference in the embeddable object)?

Compare this to how easily a collection of @Embeddable objects can be referenced using an @ElementCollection and @CollectionTable.

like image 764
ejain Avatar asked Apr 25 '17 00:04

ejain


1 Answers

Sorry for the late answer, but the question interested me so I figured I'd take a crack at it.

A more elegant solution is to make the contents of bar an Entity instead of an Embeddable, and to use a OneToOne relationship instead of an Embedded. You also need to remember to use @PrimaryKeyJoinColumn instead of @JoinColumn:

@Entity
@Table(name = "bar")
class Bar {
  @Id
  int fooId;

  String y;
  String z;
}

...

@Entity
@Table(name = "foo")
class Foo {
  @Id
  int id;

  @OneToOne
  @PrimaryKeyJoinColumn
  Bar bar;
}

The biggest advantage is that Foo no longer needs to know about the contents of Bar. Depending on your DB's naming strategy, you may also need to specify the column name of fooId in Bar with something like @Column(name = "foo_id").

like image 163
Alvin Thompson Avatar answered Oct 25 '22 22:10

Alvin Thompson