Search code examples
javajpamany-to-manybidirectional

Update bidirectional ManyToMany from both sides


referring the question Saving bidirectional ManyToMany i want to obtain exacltly what accepted answer explain as incorrect:

A a1 = new A();
A a2 = new A();
B b = new B();
a1.getB().add(b);
b.getA().add(a2);

If this state could be persisted, you would end up with the following entries in the join table:

a1_id, b_id
a2_id, b_id

But upon loading, how would JPA know that you intended to only let b know about a2 and not a1 ? and what about a2 that should not know about b ?

in my case it is correct that b knows about a1 and a2 in EVERY situation.

think about parent-child relation:

  1. b is parent of a1 AND a1 is child of b (naturally)

and for me it is erroneous to define only one direction:

  1. b is parent of a1 AND NOT a1 is child of b (???)

to obtain what accepted answer is explaining i think i need TWO join tables:

a_has_b:
a1_id, b_id

b_has_a
b_id, a2_id

am i wrong??

  1. however, how to obtain a "synchronized" bidirectional relation (not just ManyToMany)?
  2. is it possible with standard JPA features?
  3. otherwise, is there any specific provider implementation?

i think that implementing

...
public void addB(A a)
{
    getA().add(a);
    a.getB().add(this);
}

is a really ugly hack...

and using two unidirectional OneToMany on both sides does not work in EclipseLink 2.2.0 (not so sure, i'm currently trying)

thx :)


Solution

  • using two unidirectional OneToMany will do the trick:

    @Entity
    @Table
    public class A implements Serializable
    {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Basic(optional = false)
        @Column(name = "id", nullable = false)
        private Long id;
    
        @OneToMany
        @JoinTable(name="a_b", 
            joinColumns = @JoinColumn(name = "a_id", nullable = false), 
            inverseJoinColumns = @JoinColumn(name = "b_id", nullable = false)
        )
        private List<B> bList = new ArrayList<B>();
    }
    
    ---------------------------------------------------------------------------------
    
    @Entity
    @Table
    public class B implements Serializable
    {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Basic(optional = false)
        @Column(name = "id", nullable = false)
        private Long id;
    
        @OneToMany
        @JoinTable(name="a_b", 
            joinColumns = @JoinColumn(name = "b_id", nullable = false), 
            inverseJoinColumns = @JoinColumn(name = "a_id", nullable = false)
        )
        private List<A> aList = new ArrayList<A>();
    }
    

    refreshing entity will fill list