[
https://issues.apache.org/jira/browse/CAY-2792?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17685145#comment-17685145
]
Nikita Timofeev commented on CAY-2792:
--------------------------------------
[~mattraydub] Thanks for the report and for such a detailed info, test case and
even a solution analysis! As for the fix, could you please check if this patch
fixes the problem? I think we could avoid {{ConcurrentModificationException}}
as this code is using sublist and we are past iteration point.
{code:java}
@@ -63,12 +63,12 @@
DbRowOp lastRow = null;
for(DbRowOp row : sortedDbRows) {
if (row.getEntity() != lastEntity) {
- start = idx;
if(lastEntity != null && sorter.isReflexive(lastEntity)) {
ObjEntity objEntity =
resolver.getObjEntity(lastRow.getObject().getObjectId().getEntityName());
List<DbRowOp> reflexiveSublist =
sortedDbRows.subList(start, idx);
sorter.sortObjectsForEntity(objEntity, reflexiveSublist,
lastRow instanceof DeleteDbRowOp);
}
+ start = idx;
lastEntity = row.getEntity();
}
lastRow = row;
{code}
We could also try the optimizations you suggest in the master branch, while
it's just a first milestone.
> Fix Insertion Order For Reflexive DataObjects
> ---------------------------------------------
>
> Key: CAY-2792
> URL: https://issues.apache.org/jira/browse/CAY-2792
> Project: Cayenne
> Issue Type: Bug
> Components: Core Library
> Affects Versions: 4.2.RC2, 4.2.RC1
> Environment: Java 17
> Reporter: Matt Watson
> Assignee: Nikita Timofeev
> Priority: Critical
> Fix For: 4.2, 5.0.M1
>
> Time Spent: 10m
> Remaining Estimate: 0h
>
> 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.RC2}} and 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.
> The [pull request|https://github.com/apache/cayenne/pull/563] 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, 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:
> {code:java}
> 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);
> }
> {code}
>
--
This message was sent by Atlassian Jira
(v8.20.10#820010)