1️⃣ Unidirectional @OneToOne
Relationship
In a unidirectional @OneToOne
, only one entity knows about the other, and the foreign key is stored in the owning entity.
Example: A User
has a Profile
- A User has exactly one Profile.
- A Profile belongs to exactly one User.
- The foreign key (
profile_id
) is stored in theUser
table.
Step 1: Define the Owning Side (@OneToOne
with @JoinColumn
)
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
@OneToOne
@JoinColumn(name = "profile_id") // Foreign key stored in User table
private Profile profile;
}
Enter fullscreen mode Exit fullscreen mode
-
@JoinColumn(name = "profile_id")
ensures that theUser
table stores the foreign key.
Step 2: Define the Profile
Entity (No Reference Back)
@Entity
public class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String bio;
}
Enter fullscreen mode Exit fullscreen mode
-
Profile
does not referenceUser
(unidirectional). -
User
owns the relationship and has theprofile_id
column.
Generated SQL
CREATE TABLE user (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255),
profile_id BIGINT UNIQUE, -- Foreign key stored here
FOREIGN KEY (profile_id) REFERENCES profile(id)
);
CREATE TABLE profile (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
bio VARCHAR(255)
);
Enter fullscreen mode Exit fullscreen mode
The profile_id
foreign key is stored in User
, ensuring a one-to-one relationship.
Saving Data in Hibernate
Profile profile = new Profile();
profile.setBio("Software Engineer");
User user = new User();
user.setUsername("JohnDoe");
user.setProfile(profile); // Link profile to user
entityManager.persist(profile); // Save Profile first
entityManager.persist(user); // Then save User
Enter fullscreen mode Exit fullscreen mode
Now the User
is linked to the Profile
.
Querying Data
User user = entityManager.find(User.class, 1L);
System.out.println(user.getProfile().getBio()); // Works!
Enter fullscreen mode Exit fullscreen mode
You can access the Profile
from User
, but not the other way around.
2️⃣ Bidirectional @OneToOne
Relationship
In a bidirectional @OneToOne
, both entities know about each other.
Example: A User
has a Profile
, and a Profile
belongs to a User
- User owns the relationship (
@OneToOne
with@JoinColumn
). - Profile has a reference back to User (
@OneToOne(mappedBy = "profile")
).
Step 1: Define the Owning Side (@OneToOne
with @JoinColumn
)
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
@OneToOne
@JoinColumn(name = "profile_id") // Foreign key stored in User
private Profile profile;
}
Enter fullscreen mode Exit fullscreen mode
User
owns the relationship and has the foreign key.
Step 2: Define the Inverse Side (@OneToOne(mappedBy = "profile")
)
@Entity
public class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String bio;
@OneToOne(mappedBy = "profile") // Inverse side
private User user;
}
Enter fullscreen mode Exit fullscreen mode
mappedBy = "profile"
tells Hibernate:
- “The foreign key is already in the
User
table.” - “Don’t create another column in
Profile
.”
Generated SQL
CREATE TABLE user (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255),
profile_id BIGINT UNIQUE, -- Foreign key stored here
FOREIGN KEY (profile_id) REFERENCES profile(id)
);
CREATE TABLE profile (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
bio VARCHAR(255)
);
Enter fullscreen mode Exit fullscreen mode
The foreign key is only in User.profile_id
, keeping the relationship correct.
Saving Data in Hibernate
Profile profile = new Profile();
profile.setBio("Software Engineer");
User user = new User();
user.setUsername("JohnDoe");
user.setProfile(profile);
profile.setUser(user); // Set reference back
entityManager.persist(profile); // Save Profile first
entityManager.persist(user); // Then save User
Enter fullscreen mode Exit fullscreen mode
Now, both User
and Profile
reference each other.
Querying Both Directions
User → Profile
User user = entityManager.find(User.class, 1L);
System.out.println(user.getProfile().getBio()); // Works!
Enter fullscreen mode Exit fullscreen mode
Profile → User
Profile profile = entityManager.find(Profile.class, 1L);
System.out.println(profile.getUser().getUsername()); // Works!
Enter fullscreen mode Exit fullscreen mode
Unlike the unidirectional version, now you can access both User → Profile and Profile → User.
3️⃣ Summary: Unidirectional vs. Bidirectional @OneToOne
Feature | Unidirectional (@OneToOne ) |
Bidirectional (@OneToOne + mappedBy ) |
---|---|---|
@OneToOne used? |
Yes | Yes (Both Sides) |
@JoinColumn used? |
Yes (Owning Side) | Yes (Owning Side) |
mappedBy used? |
No | Yes (Inverse Side) |
Foreign key location? | In owning entity’s table | In owning entity’s table |
Reference back? | No | Yes (Both Can Access Each Other) |
Best Practice: Use bidirectional @OneToOne
if you need to query from both entities.
Unidirectional @OneToOne
is simpler if you only query in one direction.
Final Takeaways
- Unidirectional
@OneToOne
= Only one entity knows about the other (@JoinColumn
in the owning side). - Bidirectional
@OneToOne
= Both entities reference each other (mappedBy
used on the inverse side). - Always place the foreign key on the entity that owns the relationship.
- Use bidirectional if you need to query both ways.
原文链接:hibernate-008: Unidirectional vs Bidirectional @OneToOne Relationship
暂无评论内容