197

What is the difference between Unidirectional and Bidirectional associations?

Since the table generated in the db are all the same,so the only difference I found is that each side of the bidiretional assocations will have a refer to the other,and the unidirectional not.

This is a Unidirectional association

public class User {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "groupId")
    private Group   group;
}

public class Group {
    private int     id;
    private String  name;
}

The Bidirectional association

public class User {
    private int     id;
    private String  name;
    @ManyToOne
    @JoinColumn(
            name = "groupId")
    private Group   group;
}
public class Group {
    private int         id;
    private String      name;
    @OneToMany(mappedBy="group")
    private List<User>  users;
}

The difference is whether the group holds a reference of the user.

So I wonder if this is the only difference? which is recommended?

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
hguser
  • 35,079
  • 54
  • 159
  • 293

4 Answers4

206

The main difference is that bidirectional relationship provides navigational access in both directions, so that you can access the other side without explicit queries. Also it allows you to apply cascading options to both directions.

Note that navigational access is not always good, especially for "one-to-very-many" and "many-to-very-many" relationships. Imagine a Group that contains thousands of Users:

  • How would you access them? With so many Users, you usually need to apply some filtering and/or pagination, so that you need to execute a query anyway (unless you use collection filtering, which looks like a hack for me). Some developers may tend to apply filtering in memory in such cases, which is obviously not good for performance. Note that having such a relationship can encourage this kind of developers to use it without considering performance implications.

  • How would you add new Users to the Group? Fortunately, Hibernate looks at the owning side of relationship when persisting it, so you can only set User.group. However, if you want to keep objects in memory consistent, you also need to add User to Group.users. But it would make Hibernate to fetch all elements of Group.users from the database!

So, I can't agree with the recommendation from the Best Practices. You need to design bidirectional relationships carefully, considering use cases (do you need navigational access in both directions?) and possible performance implications.

See also:

Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
axtavt
  • 239,438
  • 41
  • 511
  • 482
  • Hi,thanks,seems that you are a experter of hibernate,since you have answer my question :http://stackoverflow.com/questions/5350770/mapping-a-entity-which-have-two-refer-to-another-same-entity . And now I am not sure the relationship holding,since I can not write more in the comment,so I post it here http://dpaste.de/J85m/ .Please have a check if possible.:) – hguser Mar 19 '11 at 13:30
  • @hguser: If you finally decide to make you relationship bidirectional, I think it would be better to call `setGroup()` from `addUser()` in order to hold both sides consistent. – axtavt Mar 19 '11 at 16:24
  • how about if I do not call the setGroup() inside the group.addUser()? – hguser Mar 20 '11 at 01:30
  • @hguser: Relationship wouldn't be persisted, see point 2 in the answer. You can call `setGroup()` without `addUser()`, but it would result in inconsistent state of objects in memory. – axtavt Mar 20 '11 at 12:00
  • I found that I can not a correct maping,can you spare some time to check my project at github? it is a little project. – hguser Mar 26 '11 at 09:57
  • @axtavt What do you think about `inverse=true` ? If you use `inverse=true` in a collection this collection manages `insert, update, delete` operations because of owned side – olyanren Feb 14 '15 at 11:23
  • thank you very much. any practical diagram to represent the performance. please add it – Kumaresan Perumal Aug 30 '19 at 08:34
64

There are two main differences.

Accessing the association sides

The first one is related to how you will access the relationship. For a unidirectional association, you can navigate the association from one end only.

So, for a unidirectional @ManyToOne association, it means you can only access the relationship from the child side where the foreign key resides.

If you have a unidirectional @OneToMany association, it means you can only access the relationship from the parent side which manages the foreign key.

For the bidirectional @OneToMany association, you can navigate the association in both ways, either from the parent or from the child side.

You also need to use add/remove utility methods for bidirectional associations to make sure that both sides are properly synchronized.

Performance

The second aspect is related to performance.

  1. For @OneToMany, unidirectional associations don't perform as well as bidirectional ones.
  2. For @OneToOne, a bidirectional association will cause the parent to be fetched eagerly if Hibernate cannot tell whether the Proxy should be assigned or a null value.
  3. For @ManyToMany, the collection type makes quite a difference as Sets perform better than Lists.
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • But the parent side is always the one that have the foreign key as far as I know. This two sentences seems contradictory to me. `from the child side where the foreign key resides.` `from the parent side where the foreign key resides.` – TOMAS Oct 13 '20 at 15:06
  • 3
    The FK is always on the child side. The unidirectional OneToMany manages the FK that can be in the child table on in a join table. Follow the links for more details. – Vlad Mihalcea Oct 13 '20 at 17:03
  • Hello @Vlad one question: Can many-to-many association be unidirectional? I mean performance. `@ManyToMany @JoinTable(name = "role_privileges", joinColumns = { @JoinColumn(name = "role_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "privilege_id", referencedColumnName = "id") }) private Set privileges=new HashSet();` – Alex Mar 10 '22 at 22:34
  • 3
    For Many-to-Many, it doesn't matter whether they are unidirectional or bidirectional from a performance perspective. – Vlad Mihalcea Mar 11 '22 at 06:38
13

In terms of coding, a bidirectional relationship is more complex to implement because the application is responsible for keeping both sides in synch according to JPA specification 5 (on page 42). Unfortunately the example given in the specification does not give more details, so it does not give an idea of the level of complexity.

When not using a second level cache it is usually not a problem to do not have the relationship methods correctly implemented because the instances get discarded at the end of the transaction.

When using second level cache, if anything gets corrupted because of wrongly implemented relationship handling methods, this means that other transactions will also see the corrupted elements (the second level cache is global).

A correctly implemented bi-directional relationship can make queries and the code simpler, but should not be used if it does not really make sense in terms of business logic.

13

I'm not 100% sure this is the only difference, but it is the main difference. It is also recommended to have bi-directional associations by the Hibernate docs:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/best-practices.html

Specifically:

Prefer bidirectional associations: Unidirectional associations are more difficult to query. In a large application, almost all associations must be navigable in both directions in queries.

I personally have a slight problem with this blanket recommendation -- it seems to me there are cases where a child doesn't have any practical reason to know about its parent (e.g., why does an order item need to know about the order it is associated with?), but I do see value in it a reasonable portion of the time as well. And since the bi-directionality doesn't really hurt anything, I don't find it too objectionable to adhere to.

kvista
  • 5,039
  • 1
  • 23
  • 25
  • 1
    The bi-directionality can hurt in some cases, as axtavt has explained! I would be very careful with every relation mapped in a Hibernate entity! You can end up with endless time needed for loading things in Hibernate, unless you know exactly what you're doing. Carefully think about the use cases and use different model classes for different use cases. F.ex. in a list of things, I don't need all related objects, just a label and the ID. So the list entity is a different (and very simple) one than the detail entity, for me. – cslotty Jul 14 '16 at 09:23