Michele Mariotti
Michele Mariotti

Reputation: 7459

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 :)

Upvotes: 3

Views: 4724

Answers (3)

Michele Mariotti
Michele Mariotti

Reputation: 7459

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

Upvotes: 3

James
James

Reputation: 18379

Using,

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

Is not a hack. This is good object-oriented programming. In any Java model, ignoring persistence, if you have a bi-directional relationship, you must add to both sides to correct related anything. Your code should not change just because you are, or are not, using persistence.

If you want to maintain the relationships separately, you need to have two different join tables. If you want a single ManyToMany relationship (it seems you do), then you must use @ManyToMany and set the mappedBy on one side.

See, http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany

Upvotes: 3

Basanta Raj Onta
Basanta Raj Onta

Reputation: 21

I faced the problem on updating via the non-owning side. I put @ManyToMany and @JoinTable on both side (no mappedBy). It is working nicely. I am using Hibernate 4.1.10.Final. As per wiki documents, it is not right. Confused ??

Upvotes: 1

Related Questions