JPA - One-To-One associations explained
In JPA (Java Persistence API), a one-to-one association is a type of relationship between two entities where each instance of one entity is associated with exactly one instance of another entity. This relationship is represented using the @OneToOne
annotation.
Key Points to Understand
- Cardinality:
- In a one-to-one relationship, each entity has a single corresponding entity. For example, if you have a
Person
entity and aPassport
entity, eachPerson
can have only onePassport
, and eachPassport
can be assigned to only onePerson
.
- In a one-to-one relationship, each entity has a single corresponding entity. For example, if you have a
- Owning vs. Non-Owning Side:
- Owning Side: The entity that contains the foreign key is considered the owning side of the relationship. This entity’s table will have the column that refers to the primary key of the other entity.
- Non-Owning (Inverse) Side: The other entity that does not contain the foreign key. This entity maps the relationship using the
mappedBy
attribute in the@OneToOne
annotation.
- Bidirectional and Unidirectional Relationships:
- Unidirectional: Only one entity is aware of the relationship. This means only one entity has the
@OneToOne
annotation, and the other entity has no reference to the relationship. - Bidirectional: Both entities are aware of the relationship. Each entity will have a reference to the other entity, and both will use the
@OneToOne
annotation.
- Unidirectional: Only one entity is aware of the relationship. This means only one entity has the
- Cascade Type:
- Cascade operations can be applied to propagate operations (like persist, remove) from one entity to another. This is often used in one-to-one relationships to manage both entities together.
- Fetch Type:
- By default, one-to-one relationships use
FetchType.EAGER
, meaning the related entity is fetched immediately along with the owner entity. However, you can change this toFetchType.LAZY
if you want to load the related entity on demand.
- By default, one-to-one relationships use
Example
Let’s consider an example where we have two entities: Person
and Passport
.
Entity Classes
@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "passport_id", referencedColumnName = "id")
private Passport passport;
// Getters and setters
}
@Entity
public class Passport {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String passportNumber;
@OneToOne(mappedBy = "passport")
private Person person;
// Getters and setters
}
Explanation
- Person Entity:
- The
Person
entity has apassport
field annotated with@OneToOne
, indicating that eachPerson
has onePassport
. - The
@JoinColumn
specifies the foreign key column (passport_id
) in thePerson
table that references the primary key of thePassport
entity.
- The
- Passport Entity:
- The
Passport
entity has aperson
field annotated with@OneToOne(mappedBy = "passport")
. ThemappedBy
attribute specifies that thePerson
entity owns the relationship.
- The
Database Structure
- The
Person
table will have a column namedpassport_id
, which stores the reference to the associatedPassport
entity.
Use Cases
- One-to-one relationships are commonly used in scenarios where two entities are so closely related that they should be treated as a single entity from a data model perspective, but they still represent different concepts.
By understanding these concepts, you can effectively model and manage one-to-one relationships in JPA, ensuring that your data is accurately represented and managed within your application.
The database schema
In the Person
- Passport
example with a one-to-one association in JPA, the database tables would typically look like the following:
1. Person Table
The Person
table will contain all the fields related to the Person
entity, including a foreign key that references the primary key of the Passport
table.
Table Structure: Person
Column Name | Data Type | Constraints |
---|---|---|
id | BIGINT | PRIMARY KEY, AUTO_INCREMENT |
name | VARCHAR | NOT NULL |
passport_id | BIGINT | UNIQUE, FOREIGN KEY |
id
: The primary key for thePerson
table.name
: A column to store the name of the person.passport_id
: A foreign key column that references the primary key (id
) in thePassport
table. This column is also unique because of the one-to-one relationship, ensuring that eachPerson
is associated with only onePassport
.
2. Passport Table
The Passport
table will contain all the fields related to the Passport
entity.
Table Structure: Passport
Column Name | Data Type | Constraints |
---|---|---|
id | BIGINT | PRIMARY KEY, AUTO_INCREMENT |
passport_number | VARCHAR | NOT NULL |
id
: The primary key for thePassport
table.passport_number
: A column to store the passport number.
3. Relationship in the Tables
- Person Table:
- The
passport_id
column in thePerson
table acts as a foreign key, linking eachPerson
to onePassport
. - The
UNIQUE
constraint on thepassport_id
ensures that no twoPerson
records can reference the samePassport
.
- The
- Passport Table:
- There is no need for a foreign key in the
Passport
table because thePerson
table owns the relationship.
- There is no need for a foreign key in the
Example of Table Content
Assume we have the following data in the Person
and Passport
entities:
- Person: { id: 1, name: “John Doe”, passport_id: 101 }
- Passport: { id: 101, passport_number: “X12345678” }
Person Table
id | name | passport_id |
---|---|---|
1 | John Doe | 101 |
Passport Table
id | passport_number |
---|---|
101 | X12345678 |
How They Work Together
- The
Person
table’spassport_id
column references theid
column in thePassport
table. - This setup allows for a strict one-to-one relationship, where each
Person
is associated with a uniquePassport
, and vice versa.
In this relational database design, the Person
table holds the foreign key, which is typical when one side of the relationship is considered the owner (in this case, Person
). This structure ensures the integrity and enforcement of the one-to-one relationship in the database.