Following the instructions on: Cayenne How can I help? 
<https://cayenne.apache.org/how-can-i-help.html>

I have created a JIRA issue: https://issues.apache.org/jira/browse/CAY-2792

And a pull request that includes the breaking test (without a fix yet): 
https://github.com/apache/cayenne/pull/563


Has anyone else encountered this issue? Seems like it would be a common enough 
structure, but maybe I am mistaken.

Here is the text from the JIRA issue:
> For terminology's sake, I assume Reflexive refers to when you have 2 objects 
> of the same Model, that are related, in this case, parent/child 
> (ToOne/HasMany). If this assumption is incorrect we can rename the title.
> 
> For a little history on this, we never encountered this bug until we upgraded 
> to 4.2.RC1, and I recently tested on 4.2.RC2and the bug still exists.
> 
> For a while I thought this was only a bug in our environment, thinking that 
> our code was causing the issue because Cayenne has a passing test in 
> CayenneDataObjectRelationshipsIT.testReflexiveRelationshipInsertOrder1. But 
> as I got to digging, the error occurs when the parent also has a relationship 
> to some "Other" object that is not of the same model.
> 
> My commit has a breaking test. I have not worked on a fix yet, but will begin 
> investigating. I suspect it has to do with the work done in CAY-2571 
> <https://issues.apache.org/jira/browse/CAY-2571>, but I am not certain yet.
> 
> The issue is that Cayenne randomly tries to commit the child record in front 
> of the parent record, therefore the database throws a Foreign Key error, 
> since the parent does not yet exist when the child is inserted. Because of 
> this randomness, my breaking test attempts this process 100 times. You will 
> also see another test that passes with the same Models but without setting 
> the "ToOne" Other object.
> 
> here is a look at the code that "randomly" fails:
> 
>     public void addReflexiveParentAndChildWithOtherRelationshipOnParent() {
>         // can add Reflexive Parent (that belongsTo Other) and Child,
>         // we will do this 100 times, because it randomly does it 
> correctly/incorrectly
> 
>         // given some "other" Object
>         final Other other = context.newObject(Other.class);
>         other.setName("OtherB");
>         context.commitChanges();
> 
>         final int attempts = 100;
>         int errors = 0;
> 
>         for (int i = 0; i < attempts; i++) {
>             // when parent is created and associated to "Other"
> 
>             final Reflexive parent = context.newObject(Reflexive.class);
>             parent.setName("parentB"+i);
>             parent.setToOther(other);
> 
>             // and child is created and associated to "Parent"
>             final Reflexive child = context.newObject(Reflexive.class);
>             child.setName("childB"+i);
>             child.setToParent(parent);
> 
>             try {
>                 context.commitChanges();
>             } catch (final Exception e) {
>                 errors++;
>                 e.printStackTrace();
>                 context.rollbackChanges();
>             }
>         }
> 
>         // then no error occurred
>         assertEquals(String.format("Failed on %s of %s attempts.", errors, 
> attempts), 0, errors);
>     }
>  
> 

If you would like me to elaborate more on how we use this structure in in the 
real world application I can.

Thanks for any help offered out there, as I begin digging on a solution.

Cheers,
Matt Watson
m...@swarmbox.com <mailto:m...@swarmbox.com>

Reply via email to