Repository: cayenne Updated Branches: refs/heads/master 0c3e3b68c -> 91eb2c0ae
CAY-2242 Fix from Matt Watson for multiple insertion case. Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/91eb2c0a Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/91eb2c0a Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/91eb2c0a Branch: refs/heads/master Commit: 91eb2c0aede06162de39ab27f73ccc467b14fc6e Parents: 0c3e3b6 Author: Nikita Timofeev <stari...@gmail.com> Authored: Fri Feb 24 09:56:29 2017 +0300 Committer: Nikita Timofeev <stari...@gmail.com> Committed: Fri Feb 24 09:56:29 2017 +0300 ---------------------------------------------------------------------- .../access/DataDomainFlattenedBucket.java | 67 +++++++++++++------- .../cayenne/access/VerticalInheritanceIT.java | 27 ++++++++ 2 files changed, 71 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cayenne/blob/91eb2c0a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java index b88a341..900174e 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java @@ -108,29 +108,53 @@ class DataDomainFlattenedBucket { List<FlattenedArcKey> flattenedArcKeys = entry.getValue(); DataNode node = parent.getDomain().lookupDataNode(dbEntity.getDataMap()); + + // TODO: O(N) lookup + InsertBatchQuery existingQuery = findInsertBatchQuery(queries, dbEntity); InsertBatchQuery newQuery = new InsertBatchQuery(dbEntity, 50); - boolean newQueryAdded = false; - // Here can be options with multiple arcs: - // 1. they can go as different columns in a single row - // 2. they can go as different rows in one batch - // 3. mix of both + // merge the snapshots of the FAKs by ObjectId for all ToOne relationships in case we have multiple Arcs per Object + Map<ObjectId, Map<String, Object>> toOneSnapshots = new HashMap<>(); + + // gather the list of the ToMany snapshots (these will actually be their own insert rows) + List<Map<String, Object>> toManySnapshots = new ArrayList<>(); + for (FlattenedArcKey flattenedArcKey : flattenedArcKeys) { - Map<String, Object> snapshot = flattenedArcKey.buildJoinSnapshotForInsert(node); - ObjectId objectId = null; + Map<String, Object> joinSnapshot = flattenedArcKey.buildJoinSnapshotForInsert(node); + + if (flattenedArcKey.relationship.isToMany()) { + toManySnapshots.add(joinSnapshot); + } else { + ObjectId objectId = flattenedArcKey.id1.getSourceId(); + + Map<String, Object> snapshot = toOneSnapshots.get(objectId); + + if (snapshot == null) { + toOneSnapshots.put(objectId, joinSnapshot); + } else { + // merge joinSnapshot data with existing snapshot + for (Map.Entry<String, Object> dbValue : joinSnapshot.entrySet()) { + snapshot.put(dbValue.getKey(), dbValue.getValue()); + } + } + } + } + + // apply the merged ToOne snapshots information and possibly merge it with an existing BatchQueryRow + for (Map.Entry<ObjectId, Map<String, Object>> flattenedSnapshot : toOneSnapshots.entrySet()) { + ObjectId objectId = flattenedSnapshot.getKey(); + Map<String, Object> snapshot = flattenedSnapshot.getValue(); - // TODO: O(N) lookup - InsertBatchQuery existingQuery = findInsertBatchQuery(queries, dbEntity); if (existingQuery != null) { + // TODO: O(N) lookup - BatchQueryRow existingRow = findRowForObjectId(existingQuery.getRows(), flattenedArcKey.id1.getSourceId()); + BatchQueryRow existingRow = findRowForObjectId(existingQuery.getRows(), objectId); // todo: do we need to worry about flattenedArcKey.id2 ? if (existingRow != null) { - objectId = existingRow.getObjectId(); List<DbAttribute> existingQueryDbAttributes = existingQuery.getDbAttributes(); - for (int i = 0; i < existingQueryDbAttributes.size(); i++) { + for(int i=0; i < existingQueryDbAttributes.size(); i++) { Object value = existingRow.getValue(i); if (value != null) { snapshot.put(existingQueryDbAttributes.get(i).getName(), value); @@ -140,21 +164,18 @@ class DataDomainFlattenedBucket { } newQuery.add(snapshot, objectId); + } - if (existingQuery != null) { - // replace inside arc loop, so next arc know about it - queries.remove(existingQuery); - queries.add(newQuery); - newQueryAdded = true; - // start clean query for the next arc - newQuery = new InsertBatchQuery(dbEntity, 50); - } + // apply the ToMany snapshots as new BatchQueryRows + for(Map<String, Object> toManySnapshot : toManySnapshots) { + newQuery.add(toManySnapshot); } - if(!newQueryAdded) { - // if not replaced existing query already - queries.add(newQuery); + if (existingQuery != null) { + queries.remove(existingQuery); } + + queries.add(newQuery); } } http://git-wip-us.apache.org/repos/asf/cayenne/blob/91eb2c0a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java ---------------------------------------------------------------------- diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java index 1f2d512..147e468 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java @@ -619,4 +619,31 @@ public class VerticalInheritanceIT extends ServerCase { assertEquals(other2, impl2.getOther2()); } + @Test + public void testInsertTwoObjectsWithMultipleAttributeAndMultipleRelationship() { + IvOther other1 = context.newObject(IvOther.class); + other1.setName("other1"); + + IvOther other2 = context.newObject(IvOther.class); + other2.setName("other2"); + + IvImpl impl1 = context.newObject(IvImpl.class); + impl1.setName("Impl 1"); + impl1.setAttr1("attr1"); + impl1.setAttr2("attr2"); + impl1.setOther1(other1); + impl1.setOther2(other2); + + IvImpl impl2 = context.newObject(IvImpl.class); + impl2.setName("Impl 2"); + impl2.setAttr1("attr1"); + impl2.setAttr2("attr2"); + impl2.setOther1(other1); + impl2.setOther2(other2); + + context.commitChanges(); + + assertEquals(2, ObjectSelect.query(IvImpl.class).selectCount(context)); + } + }