hibernate-008: Unidirectional vs Bidirectional @OneToOne Relationship

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 the User 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 the User 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 reference User (unidirectional).
  • User owns the relationship and has the profile_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

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容