Hello All,

We've recently upgraded to 2.3.0 (from 1.2.2) and have encountered a nasty bug 
where when loading a complicated cyclic object graph using a fetch group, some 
relationships are not being populated under some circumstances.

Unfortunately, the graph really is quite complicated, and while I have a set of 
test data where the problem can be reliably duplicated, I haven't been able to 
make an integration test do the same yet.  A simplified version of the graph is 
that A is 1:M to B and A is 1:M to C, B is M:1 to A (Bidirectional), and C is 
M:1 to A and C is also M:1 to B.  The net effect is a graph where cycles can 
exist, although in practice they generally don't other than the bidirectional 
relationship between A and B.

Our failing case is interesting.  When we load single instances of B (call them 
B1 and B2) one at a time the load is always successful, with all of the A, B, 
and C relationships populated - but only if loaded one at a time.  In other 
words, if we run entityManager.find(B1) or entityManager.find(B2), then all is 
well.

An ascii art version of the graph traversals might look something like this:

B1 -> A1 -> C1    -> B3      -> A3     -> B3        -> A3
                                                     -> B3-1     -> A3
                                                     -> B3-2     -> A3
              -> C1-2 -> ...
                  ....

B2 -> A2 -> C2    -> A3       -> B3       -> A3
                                         -> B3-1    -> A3
                                         -> B3-2    -> A3
              -> C2-2 -> ....
                   ...

where B is M:1 to A, A is 1:M to C and A is 1:M to B.

Interestingly, while B1 and B2 are separate objects, they do share several 
common objects in their graphs - call them A3 and B3 (as well as B3-1 and 
B3-2).  If we run a query that loads both B1 and B2 in the same query - 
entityManager.find(B1 + B2), then one of the relationships from one of the 
other B objects in the graph (call it B3) B3->A is null (not populated), where 
B3->A should == A3.  To clarify, B1.A1.C1.B3.getA() should equal A3, and 
instead is null, and B2.A2.C2.A3.B3.getA() should also equal A3, but instead is 
null.

Of course, the graph is being detached after load, so unfortunately lazy 
loading the B3->A relationship is not possible.

When running through a debugger, it looks like what happens is that the A3 and 
B3-* instances are each being created more than one time.  This seems to make 
sense because the graph has cycles, relationships are loaded recursively, and 
instances are not added to the transactional cache (ManagedCache) until after 
they are fully initialized with all fields loaded.   Therefore new instances 
will not always be fully created when they are needed again.  As the call stack 
goes forward, the newest A and B instances get fully initialized with all 
fields loaded.  However, as the call stack unwinds, the oldest A and B 
instances are the ones that eventually win, and one of the B instances that 
wins is not fully initialized and has a null field in it's A relationship (e.g. 
B3.getA() is null, because B3's A was not ever set).

I'm currently tracing this through to try and determine exactly why the outer 
(eldest) B3 isn't getting loaded with its A3, but while I do so, I was 
wondering if anyone else has encountered a similar problem or has any 
suggestions as to where I should focus my efforts.

My current thinking is that the multiple loading issue is OK and expected, and 
that the problem is that the oldest B's aren't getting loaded with their A's.  
But it is possible that the problem is that each individual entity should only 
be initialized once, and that the problem is that OpenJPA is instantiated 
multiple copies of each B and A and should only ever be instantiating one per 
id.  Comments would be welcome.


Thanks,

Jeff

[http://elasticpath.com/images/ep.gif]
Jeff Oh, Sr. Software Engineer
Phone: 604.408.8078 ext. 104
Email: jeff...@elasticpath.com<mailto:jeff...@elasticpath.com>

Elastic Path Software Inc.
Web elasticpath.com <http://www.elasticpath.com/> | Blog getelastic.com 
<http://www.getelastic.com/> | Twitter twitter.com/elasticpath 
<http://www.twitter.com/elasticpath>
Careers elasticpath.com/jobs<http://www.elasticpath.com/jobs> | Community 
grep.elasticpath.com <http://grep.elasticpath.com/>

Confidentiality Notice: This message is intended only for the use of the 
designated addressee(s), and may contain information that is privileged, 
confidential and exempt from disclosure. Any unauthorized viewing, disclosure, 
copying, distribution or use of information contained in this e-mail is 
prohibited and may be unlawful. If you received this e-mail in error, please 
reply to the sender immediately to inform us you are not the intended recipient 
and delete the email from your computer system.



Reply via email to