Announcement Announcement Module
Collapse
No announcement yet.
Managing bidirectional many-to-many associations in Hibernate Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Managing bidirectional many-to-many associations in Hibernate

    Hi everyone,

    in my project, we have manytomany associations of the form:


    Code:
    class Booking {
    List<Wagon> wagons;
    }
    
    class Wagon {
    List<Bookings> bookings;
    }

    I know that one side of a manytomany relation is the owning side and only
    this side is used to update the association table.
    Though updating one side of the association is enough, we would like to keep the object state consistent with the database
    state to avoid misinterpretations.

    I recently joined "Spring With Hibernate" course of SpringSource and there I learned that, in onetomany relations the one-side's methods update the relation in both sides by convention such as:

    Code:
    class Person {
       addDog(Dog d) {
          mydogs.add(d);
          d.setOwner(this);
       }
    }
    Is there any similar convention to manage the object state of manytomany relations?

    What I can think of is:

    Code:
    //owning side
    class Booking {
       List<Wagon> wagons;
    
       addWagonsBidirectional(Wagon wg) {
         wagons.add(wg);
         wg.getBookings.add(this);
       }
    }
    
    //inverse side
    class Wagon {
       List<Bookings> bookings;
    
       getBookings() {
          return bookings;
       }
    }
    In that case we would (by convention) alwaws use the owning side as
    responsible side for keeping relation state correct.

    I did post a similar question in Hibernate Forums, but did not get any suggestions.
    https://forum.hibernate.org/viewtopic.php?f=1&t=1024265

    Many thanks in advance!

  • #2
    Hi,

    The first time I worked with bidirectional relationships I have created a code like this (using Set instead of List):

    Code:
    public static void addManyToMany(Booking object, Wagon self) {
    
        Set<Booking> objectSet = self.getBookings();
        if (objectSet == null) {
            objectSet = new HashSet<Booking>();
            self.setBookings(objectSet);
        }
    
        if (!objectSet.contains(object)) {
            objectSet.add(object);
            Set<Wagon> selfSet = object.getWagons();
            if (selfSet == null) {
                selfSet = new HashSet<Wagon>();
                object.setWagons(selfSet);
            }
            selfSet.add(self);
        }
    }
    In fact, in the code I used, this method was using generics (and something more to avoid using reflection) so it could be used for all many-to-many bidirectional relationships. Then in the "addWagonsBidirectional" method I would only call the "addManyToMany" passing the parameters in the right order.

    There are a few differences compared to what you suggested:

    1 - it checks wheter or not the collections are created (so we don't need to create empty collections if we are not going to use them
    2 - it checks is the element is not already in there

    I also had "add" and "remove" methods for all "toMany" sides of relationships, so the only work I had to do was to make a single call per relationship from all my entity classes. For the "toOne" side of relationships I had the "set" method implemented the same way.

    In a second project using this approach I have created some great improvements on top of this initial idea:

    a - created a Maven plug-in that manipulates the bytecodes of my entity classes to call those relationship management methods for me, so I only had to declare those methods as abstract
    b - the methods "add" and "remove" were made private and they were called automatically by collection proxies: this means that now it is possible to add a wagon to a booking using this code "booking.getWagons().add(wagon)", and this would automatically update the other side of the relationship
    c - relationships could be even managed using iterators taken from the collection classes
    d - the relationship method would also check if live entities were not mixed with detached ones (what could lead to second level cache inconsistencies)

    Comment


    • #3
      I have created this new thread:

      http://forum.springsource.org/showth...ndling-methods

      out of this one, to talk about automatic generation of bidirectional relationship methods.

      Comment

      Working...
      X