DEV Community

Hunor Vadasz-Perhat
Hunor Vadasz-Perhat

Posted on

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.

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

πŸ‘₯ Ideal for solo developers, teams, and cross-company projects

Learn more