In this tutorial, we’ll how to implement one to one relationship mapping in JPA with database table and schema example. There might be different use case to implementing one to one relationship. For example, one user will have only one user profile.

Lets say we are developing a User Management System and we want to add mailing address feature. Every user will have only have one mailing address. So in this case, we need to create one-to-one relationship between user
and address
entity or tables. Learn How to Connect PostgreSQL Database in Spring Boot Project.
We can implement one-to-one mapping in 3 different ways:
- Using Foreign Key
- Using Shared Primary Key
- Using Join Table
1. Using Foreign Key
Lets create a User
class with table name users
.
@Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; //... @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "address_id", referencedColumnName = "id") private Address address; // ... getters and setters }
If you see above, we have added @OneToOne
annotation on address
field. Also, we need to place the @JoinColumn
annotation to configure the name of the column in the users table that maps to the primary key in the address table.
@Entity @Table(name = "address") public class Address { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; //... @OneToOne(mappedBy = "address") private User user; //... getters and setters }
In address
entity, we have also added @OnetoOne
for bidirectional relationship.
Bellow is table definition created from above entities using foreign key:
Table "users" Column | Type | Collation | Nullable | Default ------------+-----------------------------+-----------+----------+--------- id | bigint | | not null | email | character varying(255) | | not null | first_name | character varying(255) | | | last_name | character varying(255) | | | address_id | bigint | | | Indexes: "users_pkey" PRIMARY KEY, btree (id) "uk_6dotkott2kjsp8vw4d0m25fb7" UNIQUE CONSTRAINT, btree (email) Foreign-key constraints: "fkditu6lr4ek16tkxtdsne0gxib" FOREIGN KEY (address_id) REFERENCES address(id)
Table "address" Column | Type | Collation | Nullable | Default --------+------------------------+-----------+----------+--------- id | bigint | | not null | name | character varying(255) | | | Indexes: "address_pkey" PRIMARY KEY, btree (id) Referenced by: TABLE "users" CONSTRAINT "fkditu6lr4ek16tkxtdsne0gxib" FOREIGN KEY (address_id) REFERENCES address(id)
2. One-to-One Relationship using Shared Primary Key
In this one to one strategy, instead of creating a new column address_id
, we’ll mark the primary key column user_id
of the address table as the foreign key to the users table.
@Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; //... @OneToOne(mappedBy = "user", cascade = CascadeType.ALL) @PrimaryKeyJoinColumn private Address address; //... getters and setters }
@Entity @Table(name = "address") public class Address { @Id @Column(name = "user_id") private Long id; //... @OneToOne @MapsId @JoinColumn(name = "user_id") private User user; //... getters and setters }
The mappedBy
attribute is now in User
class since the foreign key is now present in the address
table. We have also added the @PrimaryKeyJoinColumn
annotation, which indicates that the primary key of the User
entity is used as the foreign key value for the associated Address
entity. Also @MapsId
annotation, which indicates that the primary key values will be copied from the User
entity.
Bellow is table definition created from above entities using shared primary key:
Table "users" Column | Type | Collation | Nullable | Default ------------+-----------------------------+-----------+----------+--------- id | bigint | | not null | email | character varying(255) | | not null | first_name | character varying(255) | | | last_name | character varying(255) | | | password | character varying(255) | | not null | role | character varying(255) | | | Indexes: "users_pkey" PRIMARY KEY, btree (id) "uk_6dotkott2kjsp8vw4d0m25fb7" UNIQUE CONSTRAINT, btree (email) Referenced by: TABLE "address" CONSTRAINT "fk6i66ijb8twgcqtetl8eeeed6v" FOREIGN KEY (user_id) REFERENCES users(id)
Table "address" Column | Type | Collation | Nullable | Default ---------+------------------------+-----------+----------+--------- user_id | bigint | | not null | name | character varying(255) | | | Indexes: "address_pkey" PRIMARY KEY, btree (user_id) Foreign-key constraints: "fk6i66ijb8twgcqtetl8eeeed6v" FOREIGN KEY (user_id) REFERENCES users(id)
I personally like to implement this relationship in my projects.
3. Using Join Table in JPA
Lets create relationship using @JoinTable
.
@Entity @Table(name = "employee") public class Employee { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; //... @OneToOne(cascade = CascadeType.ALL) @JoinTable(name = "emp_workstation", joinColumns = { @JoinColumn(name = "employee_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "workstation_id", referencedColumnName = "id") }) private WorkStation workStation; //... getters and setters }
@Entity @Table(name = "workstation") public class WorkStation { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private Long id; //... @OneToOne(mappedBy = "workStation") private Employee employee; //... getters and setters }