Deal of the Day

Home » Main » Manning Forums » 2006 » EJB3 in Action

Thread: mappedBy side of a ManyToMany bidirectional relationship is not populating

Reply to this Thread Reply to this Thread Search Forum Search Forum Back to Thread List Back to Thread List

Permlink Replies: 6 - Pages: 1 - Last Post: Oct 7, 2008 5:04 PM by: MHarv Threads: [ Previous | Next ]
MHarv

Posts: 4
Registered: 10/2/08
mappedBy side of a ManyToMany bidirectional relationship is not populating
Posted: Oct 2, 2008 4:45 PM
  Click to reply to this thread Reply

It seems that when I have a @ManyToMany bidirectional relationship between two entities, I'm only getting access to the owning side. The two entites I'm looking at are A and B - when I define the many-to-many in A as: @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name="SchemaName.A_B_ASSOC", joinColumns={ @JoinColumn( name="A_ID", referencedColumnName="A_ID" ) }, inverseJoinColumns={ @JoinColumn( name="B_ID", referencedColumnName="B_ID" ) } ) private Collection associatedBs; ... during execution I can see that an "A" object has a collection of B objects. Looks good. However, in the B object I also defined the mappedBy side ... @ManyToMany(mappedBy = "associatedBs") private Collection associatedAs; ... and during that same execution, when I look into a B object, its Collection of A objects has size = 0. If I have the owning side working, and I can see an object B within an object A ... why doesn't that same object B show me that object A in it's collection? Thank you very much for any insight! - MHarv

reza_rahman


Posts: 448
From: Philadelphia ,PA
Registered: 11/30/05
Re: mappedBy side of a ManyToMany bidirectional relationship is not populating
Posted: Oct 2, 2008 5:27 PM   in response to: MHarv in response to: MHarv
  Click to reply to this thread Reply

Hmm...can you show me the code that you are using to add and count entities?

Remember, unlike EJB 2.x Entity Beans, JPA does not automatically update bi-directional relationships since entities are not really managed by a container. We cover this in a side-bar titled "RIP: container-managed relationships" on page 249. So the following won't work:

Person person = new Person();
Address home = new Address();
Address work = new Address();
person.addAddress(home);
person.addAddress(work);

entityManager.persist(person);

int addressCount = person.getAddresses(); // addressCount == 2.
int personCount = work.getPersons(); // personCount == 0.

In order to get the right personCount, you'll need a round-trip to the database like so:

entityManager.flush();
entityManager.refresh(work);
int personCount = work.getPersons(); // personCount > 0 (probably == 1).

Does that help?

Cheers,
Reza

MHarv

Posts: 4
Registered: 10/2/08
Re: mappedBy side of a ManyToMany bidirectional relationship is not populating
Posted: Oct 3, 2008 2:58 PM   in response to: reza_rahman in response to: reza_rahman
  Click to reply to this thread Reply

Thanks for your response! And let me apologize for how my initial question got formatted - I've reformatted that bit and pasted it to the bottom of this post.

To your questions:
I'm not using code to count entities, I am using a debug process (JDeveloper) which allows me to navigate into the objects.

Also, this isn't during an update - I'm using the EntityManager and a NamedQuery to instantiate an object of the first type from the database, and my expectation was that the many-to-many relationship as defined on the attributes of each object would take care of populating the Collections on each object. This is working on the owning side - my object "A" as returned from the NamedQuery has the complete Collection of object "B"s. It's just that those object "B"s don't have anything in their Collection of A's, and I think that they should.

I think that the answer you gave refers to Cascades, and I'll have to deal with that when I get to it. But I believe that what I'm referring to now has to do with FetchType.EAGER, and that it's not behaving correctly on the mappedBy side of the relationship.

Again, thanks for any help.
- Matt

(Below is the pseudo-snippet of code I tried to give you last time - I've changed the angle-brackets to carats so that they're not HTML'd....)

Here's the annotation/attribute defined in object A:

@ManyToMany(fetch = FetchType.EAGER) @JoinTable(name="SchemaName.A_B_ASSOC",
joinColumns={
@JoinColumn(
name="A_ID",
referencedColumnName="A_ID"
)
},
inverseJoinColumns={
@JoinColumn(
name="B_ID",
referencedColumnName="B_ID"
)
}
)
private Collection^B^ associatedBs;

... during execution I can see that an "A" object has a collection of B objects. Looks good. However, in the B object I also defined the mappedBy side ...

@ManyToMany(mappedBy = "associatedBs")
private Collection^A^ associatedAs;

... and during that same execution, when I look into a B object, its Collection of A objects has size = 0

reza_rahman


Posts: 448
From: Philadelphia ,PA
Registered: 11/30/05
Re: mappedBy side of a ManyToMany bidirectional relationship is not populating
Posted: Oct 3, 2008 4:29 PM   in response to: MHarv in response to: MHarv
  Click to reply to this thread Reply

OK...try: @ManyToMany(mappedBy = "associatedBs", fetch = FetchType.EAGER) private Collection associatedAs; Many-to-many relationships are loaded lazily by default. Normally, the relationship is loaded when you first access it, but the debugger might be messing with that. Hope it helps, Reza

MHarv

Posts: 4
Registered: 10/2/08
Re: mappedBy side of a ManyToMany bidirectional relationship is not populating
Posted: Oct 6, 2008 10:09 AM   in response to: reza_rahman in response to: reza_rahman
  Click to reply to this thread Reply

First, isn't this unnecessary? I thought that @ManyToMany parameters from the owning side are applied to the mappedBy side via the EntityManager?

Second, I tried this, and now I'm getting an error that "table or view is not found" ... how is that possible? The table I'm referring to is found just fine using the owning side, it's obviously the same table from the mappedBy side ... the only thing I can see in the error message is that the schema name for the table has been stripped off. Have you ever heard of that? Would the EntityManager strip off the schema name for the mappedBy side ... and if so why?

The work-around I currently have in place is to set up both sides as "owning". I've copied the @JoinTables and reversed the @JoinColumns into both objects, and now everything is populating correctly and there are no errors that I've seen yet. However, this workaround does not seem to me like a good idea, and definitely makes me question my understanding of how bidirectional many-to-many is supposed to work.

Please let me know if you have any more insight on this.
Thank you.

reza_rahman


Posts: 448
From: Philadelphia ,PA
Registered: 11/30/05
Re: mappedBy side of a ManyToMany bidirectional relationship is not populating
Posted: Oct 6, 2008 12:24 PM   in response to: MHarv in response to: MHarv
  Click to reply to this thread Reply

Many-to-many ORM mappings are propagated to the non-owning side, entity loading options are not (doesn't really make such sense otherwise since usage patterns can be completely different).

Could you post your modified code? Also, what persistence provider are you using? Hibernate? TopLink? Hibernate is known to have strange handling of some ORM mappings (take a look at some previous threads in the forum). If that's the case, I would ask you to pursue this further in the Hibernate forums instead of here.

For future reference, you can also take a look at the SQL log to see what the persistence provider is trying to do under the hood...that often shed's light on subtle issues. Just out of curiousity, have you checked if lazy loading is working? If it isn't you might have more basic ORM mapping issues to begin with...

Cheers,
Reza

MHarv

Posts: 4
Registered: 10/2/08
Re: mappedBy side of a ManyToMany bidirectional relationship is not populating
Posted: Oct 7, 2008 5:04 PM   in response to: reza_rahman in response to: reza_rahman
  Click to reply to this thread Reply

To answer each of your questions / comments ...

I'll take your note regarding entity loading options not being propogated from owning to mappedBy under advisement - this was a misunderstanding on my part.

The persistence provider I'm currently using is toplink 1.0 (which I believe is only the Specification Version - the Implementation Version is listed in the manifest file as 2.0 b41-beta2).

I will take a look at the SQL log to see if I can glean any information from that. I'm also going to try using some alternate JPA providers.

Your note on Lazy Loading worries me ... I got a lot of errors at various points of development saying that Lazy Loading was a problem, so I changed to Eager. I may have been masking real issues with my code. I will try to remove Eager loading piece by piece to see if I can address any underlying issues.


As for the modified code for my work around, it's pretty much the same as the examples I've already posted. In Object A ...


@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name="SchemaName.A_B_ASSOC",
joinColumns={@JoinColumn(name="A_ID", referencedColumnName="A_ID")},
inverseJoinColumns={@JoinColumn(name="B_ID", referencedColumnName="B_ID")}
)
private Collection^B^ associatedBs;

... and then in Object B ...

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name="SchemaName.A_B_ASSOC",
joinColumns={@JoinColumn(name="B_ID", referencedColumnName="B_ID")},
inverseJoinColumns={@JoinColumn(name="A_ID", referencedColumnName="A_ID")}
)
private Collection^A^ associatedAs;

... so there is no "mappedBy". And now when my Object A is instantiated via the EntityManager, it has a fully populated Collection of associatedBs and each of those Bs have fully populated Collections of associatedAs.


Once again, thanks very much for your help. I've got some topics to pursue, and I'll post back with information if anything clears this up. Otherwise, unless you've got more ideas, I'll assume I'm on my own until I've followed all of these leads. Thanks.

Legend
Gold: 300 + pts
Silver: 100 - 299 pts
Bronze: 25 - 99 pts
Manning Author
Manning Staff
Manning Developmental Editor