2.2.5. Mapping entity bean associations/relationships
2.2.5.1. One-to-one
You can associate entity beans through a one-to-one relationship using
@OneToOne
. There are three cases for one-to-one associations: either the associated entities share the same primary keys values, a foreign key is held by one of the entities (note that this FK column in the database should be constrained unique to simulate one-to-one multiplicity), or a association table is used to store the link between the 2 entities (a unique constraint has to be defined on each fk to ensure the one to one multiplicity)
First, we map a real one-to-one association using shared primary keys:
@Entity public class Body { @Id public Long getId() { return id; } @OneToOne(cascade = CascadeType.ALL) @PrimaryKeyJoinColumn public Heart getHeart() { return heart; } ... }
@Entity public class Heart { @Id public Long getId() { ...} }
The one to one is marked as true by using the
@PrimaryKeyJoinColumn
annotation.
In the following example, the associated entities are linked through a foreign key column:
@Entity public class Customer implements Serializable { @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="passport_fk") public Passport getPassport() { ... } @Entity public class Passport implements Serializable { @OneToOne(mappedBy = "passport") public Customer getOwner() { ... }
A
Customer
is linked to a Passport
, with a foreign key column named passport_fk
in the Customer
table. The join column is declared with the @JoinColumn
annotation which looks like the @Column
annotation. It has one more parameters named referencedColumnName
. This parameter declares the column in the targeted entity that will be used to the join. Note that when using referencedColumnName
to a non primary key column, the associated class has to be Serializable
. Also note that the referencedColumnName
to a non primary key column has to be mapped to a property having a single column (other cases might not work).
The association may be bidirectional. In a bidirectional relationship, one of the sides (and only one) has to be the owner: the owner is responsible for the association column(s) update. To declare a side as not responsible for the relationship, the attribute
mappedBy
is used. mappedBy
refers to the property name of the association on the owner side. In our case, this is passport
. As you can see, you don't have to (must not) declare the join column since it has already been declared on the owners side.
If no
@JoinColumn
is declared on the owner side, the defaults apply. A join column(s) will be created in the owner table and its name will be the concatenation of the name of the relationship in the owner side, _ (underscore), and the name of the primary key column(s) in the owned side. In this example passport_id
because the property name is passport
and the column id of Passport
is id
.
The third possibility (using an association table) is very exotic.
@Entity public class Customer implements Serializable { @OneToOne(cascade = CascadeType.ALL) @JoinTable(name = "CustomerPassports", joinColumns = @JoinColumn(name="customer_fk"), inverseJoinColumns = @JoinColumn(name="passport_fk") ) public Passport getPassport() { ... } @Entity public class Passport implements Serializable { @OneToOne(mappedBy = "passport") public Customer getOwner() { ... }
A
Customer
is linked to a Passport
through a association table named CustomerPassports
; this association table has a foreign key column named passport_fk
pointing to the Passport
table (materialized by the inverseJoinColumn
, and a foreign key column named customer_fk
pointing to the Customer
table materialized by the joinColumns
attribute.
You must declare the join table name and the join columns explicitly in such a mapping.