one to one
This commit is contained in:
parent
f012afe95f
commit
33a3af7abc
|
@ -34,6 +34,12 @@ An entity must:
|
|||
|
||||
On the other hand, the entity class may be either concrete or `abstract`, and it may have any number of additional constructors.
|
||||
|
||||
[TIP]
|
||||
.Inner entity classes
|
||||
====
|
||||
An entity class may be a `static` inner class.
|
||||
====
|
||||
|
||||
Every entity class must be annotated `@Entity`.
|
||||
|
||||
[source,java]
|
||||
|
@ -694,19 +700,32 @@ The `@ManyToOne` annotation marks the "one" side of the association, and so a un
|
|||
[source,java]
|
||||
----
|
||||
class Book {
|
||||
...
|
||||
@ManyToOne
|
||||
@Id @GeneratedValue
|
||||
Long id;
|
||||
|
||||
@ManyToOne(fetch=LAZY)
|
||||
Publisher publisher;
|
||||
...
|
||||
}
|
||||
----
|
||||
|
||||
[TIP]
|
||||
.Almost all associations should be lazy
|
||||
====
|
||||
A very unfortunate misfeature of JPA is that `@ManyToOne` associations are fetched eagerly by default.
|
||||
This is almost never what we want.
|
||||
The only scenario in which `fetch=EAGER` makes sense is if we think there's always a _very_ high probability that the associated object will be found in the second-level cache.
|
||||
Whenever this isn't the case, remember to explicitly specify `fetch=LAZY`.
|
||||
====
|
||||
|
||||
To make this association bidirectional, we need to add a collection-valued attribute to the `Publisher` class, and annotate it `@OneToMany`, using the `mappedBy` member to refer back to `Book.publisher`.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
class Publisher {
|
||||
...
|
||||
@Id @GeneratedValue
|
||||
Long id;
|
||||
|
||||
@OneToMany(mappedBy="publisher")
|
||||
Set<Book> books;
|
||||
...
|
||||
|
@ -761,6 +780,92 @@ Now? I guess we're happy to let you guys decide.
|
|||
In hindsight, we could have done more to make clear that this was always a viable option.
|
||||
====
|
||||
|
||||
[[one-to-one-fk]]
|
||||
=== One to one (first way)
|
||||
|
||||
The simplest sort of one to one association is almost exactly line a `@ManyToOne` association, except that it maps to a foreign key column with a `UNIQUE` constraint.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Entity
|
||||
static class Author {
|
||||
@Id @GeneratedValue
|
||||
Long id;
|
||||
|
||||
@OneToOne(optional=false, fetch=LAZY)
|
||||
Person author;
|
||||
|
||||
...
|
||||
}
|
||||
----
|
||||
|
||||
We can make this association bidirectional by adding a reference back to the `Author` in the `Person` entity:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Entity
|
||||
static class Person {
|
||||
@Id @GeneratedValue
|
||||
Long id;
|
||||
|
||||
@OneToOne(mappedBy = "person")
|
||||
Author author;
|
||||
|
||||
...
|
||||
}
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
.Lazy fetching for one to one associations
|
||||
====
|
||||
Notice that we did not declare the unowned end of the association `fetch=LAZY`.
|
||||
That's because:
|
||||
|
||||
1. not every `Person` has an associated `Author`, and
|
||||
2. the foreign key is held in the table mapped by `Author`, not in the table mapped by `Person`.
|
||||
|
||||
Therefore, Hibernate can't tell if the reference from `Person` to `Author` is `null` without fetching the associated `Author`.
|
||||
|
||||
On the other hand, if _every_ `Person` was an `Author`, that is, if the association were non-`optional`, we would not have to consider the possibility of `null` references, and we would map it like this:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@OneToOne(optional=false, mappedBy = "person", fetch=LAZY)
|
||||
Author author;
|
||||
----
|
||||
====
|
||||
|
||||
This is not the only sort of one to one association.
|
||||
|
||||
[[one-to-one-pk]]
|
||||
=== One to one (second way)
|
||||
|
||||
An arguably more elegant way to represent such a relationship is to share a primary key between the two tables.
|
||||
That is, the foreign key would be the primary key.
|
||||
|
||||
To use this approach, the `Author` class must be annotated like this:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Entity
|
||||
static class Author {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@OneToOne(optional=false, fetch=LAZY)
|
||||
@MapsId
|
||||
Person author;
|
||||
|
||||
...
|
||||
}
|
||||
----
|
||||
|
||||
Notice that the `@Id` attribute is no longer a `@GeneratedValue` and, instead, the `author` association is annotated `@MapsId`.
|
||||
This lets Hibernate know that the association to `Person` is the source of primary key values for `Author`.
|
||||
That is, that the foreign key column referring to the `Author` table is also the primary key of the `Person` table.
|
||||
|
||||
The `Person` class does not change.
|
||||
If the association is bidirectional, we annotate the unowned side `@OneToOne(mappedBy = "person")` just as before.
|
||||
|
||||
|
||||
[[equals-and-hash]]
|
||||
|
|
Loading…
Reference in New Issue