Hibernate Best Practices: Avoiding Many-To-Many and 'exotic' relationships
Asked Answered
K

3

9

The hibernate best practices states that many-to-many associations are rare and should be avoided.

Do not use exotic association mappings:

Practical test cases for real many-to-many associations are rare. Most of the time you need additional information stored in the "link table". In this case, it is much better to use two one-to-many associations to an intermediate link class. In fact, most associations are one-to-many and many-to-one. For this reason, you should proceed cautiously when using any other association style.

A basic and common case would be: user can be in more than one team and a team can have more than one member.

Is there an alternative to using @ManyToMany, other than creating an entity for the join table? In the case of team/member, there is no additional data in the join table, so having Team>TeamMembership>User is not so practical.

Koball answered 3/9, 2013 at 13:58 Comment(0)
R
11

There is nothing intrinsically wrong with using @ManyToMany but in practice, you rarely have the opportunity to use it. Usually you need additional attributes on the link itself, at which point, the relationship becomes an entity of its own.

One example from my experience was the kind of person/team relationship you described. I used a @ManyToMany at first, but had to turn it into a @OneToMany once I needed to add an effective-date on the relationship (person belongs to team at specific point in time).

Robber answered 3/9, 2013 at 14:3 Comment(0)
T
6

One of the problems with @ManyToMany is that models change. If you need to add a field to the association, then you have a few choices. You can either refactor the model so that the association becomes an entity (read link class). Or you can make the association even more exotic, for example @MapKeyJoinColumn. In either case, the future refactoring effort could be saved by designing the model right in the first place.

Furthermore, using one of these exotic many-to-many mappings tends to bring the model closer to edge cases where test coverage is lower and real world usage is lower. This in turn increases the risk of encountering unsupported or undersupported features as well as unresolved and undiscovered bugs.

Finally just because hibernate gives you a way to do it, doesn't mean you should use it. I've seen too many cases in my experience of developers using a certain feature in hibernate a way it was not intended which led to other design implications, and limitations that caused more trouble and headaches than they were worth.

Tourneur answered 24/1, 2014 at 5:30 Comment(0)
I
0

The best practice in agile programming is to use the simplest implementation. You don't have a crystal ball to know that in the future you will need additional information on the link table. So best practice suggest to use @ManyToMany because you can always add a field and a new class.

But, also I suggest to look carefully for the bidirectional associations between two objects. Even the relation is many-to-many, you should prefer unidirectional associations.

I suggest to look into the "Refactoring" book (Martin Fowler):

The refactoring on web, and an excerpt from the book (is not on the site):

"Bidirectional associations are useful, but they carry a price. The price is the added complexity of maintaining the two-way links and ensuring that objects are properly created and removed. Bidirectional associations are not natural for many programmers, so they often are a source of errors.

Lots of two-way links also make it easy for mistakes to lead to zombies: objects that should be dead but still hang around because of a reference that was not cleared.

Bidirectional associations force an interdependency between the two classes. Any change to one class may cause a change to another. If the classes are in separate packages, you get an interdependency between the packages. Many interdependencies lead to a highly coupled system, in which any little change leads to lots of unpredictable ramifications. You should use bidirectional associations when you need to but not when you don't. As soon as you see a bidirectional association is no longer pulling its weight, drop the unnecessary end."

Also look at the CQRS. Especially on command part. Maybe you only need to traverse the relation in one direction only.

And look also at the "Aggregate" pattern. Clients traverse the aggregate from root because they load the whole aggregate all the time.

Impregnate answered 24/5 at 9:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.