You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2022/06/30 15:08:09 UTC

[cayenne] 07/09: CAY-2737 Cayenne 4.3: cleanup deprecated code - delete LegacyDataDomainFlushAction

This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 4e1bd02c6c0a4ca42321b4d1f5688cf460829f92
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Thu Jun 30 18:00:18 2022 +0300

    CAY-2737 Cayenne 4.3: cleanup deprecated code
     - delete LegacyDataDomainFlushAction
---
 .../cayenne/access/DataDomainDBDiffBuilder.java    | 252 --------------
 .../cayenne/access/DataDomainDeleteBucket.java     | 128 --------
 .../cayenne/access/DataDomainFlattenedBucket.java  | 208 ------------
 .../cayenne/access/DataDomainFlushObserver.java    | 162 ---------
 .../access/DataDomainIndirectDiffBuilder.java      | 178 ----------
 .../cayenne/access/DataDomainInsertBucket.java     | 237 --------------
 .../cayenne/access/DataDomainSyncBucket.java       | 278 ----------------
 .../cayenne/access/DataDomainUpdateBucket.java     | 157 ---------
 .../access/DataNodeSyncQualifierDescriptor.java    | 162 ---------
 .../java/org/apache/cayenne/access/DbArcId.java    |  96 ------
 .../cayenne/access/DbEntityClassDescriptor.java    | 111 -------
 .../org/apache/cayenne/access/FlattenedArcKey.java | 362 ---------------------
 .../access/LegacyDataDomainFlushAction.java        | 271 ---------------
 .../access/LegacyDataDomainFlushActionFactory.java |  45 ---
 14 files changed, 2647 deletions(-)

diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDBDiffBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDBDiffBuilder.java
deleted file mode 100644
index 013a201f8..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDBDiffBuilder.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.access.DataDomainSyncBucket.PropagatedValueFactory;
-import org.apache.cayenne.exp.parser.ASTDbPath;
-import org.apache.cayenne.graph.ArcId;
-import org.apache.cayenne.graph.GraphChangeHandler;
-import org.apache.cayenne.graph.GraphDiff;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- * Processes object diffs, generating DB diffs. Can be used for both UPDATE and
- * INSERT.
- * 
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainDBDiffBuilder implements GraphChangeHandler {
-
-    private ObjEntity objEntity;
-    private DbEntity dbEntity;
-
-    // diff snapshot expressed in terms of object properties.
-    private Map<Object, Object> currentPropertyDiff;
-    private Map<Object, Object> currentArcDiff;
-    private Object currentId;
-
-    /**
-     * Resets the builder to process a new combination of objEntity/dbEntity.
-     */
-    void reset(DbEntityClassDescriptor descriptor) {
-        this.objEntity = descriptor.getEntity();
-        this.dbEntity = descriptor.getDbEntity();
-    }
-
-    /**
-     * Resets the builder to process a new object for the previously set
-     * combination of objEntity/dbEntity.
-     */
-    private void reset() {
-        currentPropertyDiff = null;
-        currentArcDiff = null;
-        currentId = null;
-    }
-
-    /**
-     * Processes GraphDiffs of a single object, converting them to DB diff.
-     */
-    Map<String, Object> buildDBDiff(GraphDiff singleObjectDiff) {
-
-        reset();
-        singleObjectDiff.apply(this);
-
-        if (currentPropertyDiff == null && currentArcDiff == null && currentId == null) {
-            return null;
-        }
-
-        Map<String, Object> dbDiff = new HashMap<>();
-
-        appendSimpleProperties(dbDiff);
-        appendForeignKeys(dbDiff);
-        appendPrimaryKeys(dbDiff);
-
-        return dbDiff.isEmpty() ? null : dbDiff;
-    }
-
-    private void appendSimpleProperties(Map<String, Object> dbDiff) {
-        // populate changed columns
-        if (currentPropertyDiff != null) {
-            for (final Map.Entry<Object, Object> entry : currentPropertyDiff.entrySet()) {
-                ObjAttribute attribute = objEntity.getAttribute(entry.getKey().toString());
-
-                // In case of a flattened attribute, ensure that it belongs to this bucket...
-                DbAttribute dbAttribute = attribute.getDbAttribute();
-                if (dbAttribute.getEntity() == dbEntity) {
-                    dbDiff.put(dbAttribute.getName(), entry.getValue());
-                }
-            }
-        }
-    }
-
-    private void appendForeignKeys(Map<String, Object> dbDiff) {
-        // populate changed FKs
-        if (currentArcDiff != null) {
-            for (Entry<Object, Object> entry : currentArcDiff.entrySet()) {
-
-                DbRelationship dbRelation;
-
-                String arcIdString = entry.getKey().toString();
-                ObjRelationship relation = objEntity.getRelationship(arcIdString);
-                if (relation == null) {
-                    dbRelation = dbEntity.getRelationship(arcIdString.substring(ASTDbPath.DB_PREFIX.length()));
-                } else {
-                    dbRelation = relation.getDbRelationships().get(relation.getDbRelationships().size() - 1);
-                }
-
-                // In case of a vertical inheritance, ensure that it belongs to this bucket...
-                if (dbRelation.getSourceEntity() == dbEntity) {
-                    ObjectId targetId = (ObjectId) entry.getValue();
-                    for (DbJoin join : dbRelation.getJoins()) {
-                        Object value = (targetId != null)
-                                ? new PropagatedValueFactory(targetId, join.getTargetName())
-                                : null;
-
-                        dbDiff.put(join.getSourceName(), value);
-                    }
-                }
-            }
-        }
-    }
-
-    private void appendPrimaryKeys(Map<String, Object> dbDiff) {
-
-        // populate changed PKs; note that we might end up overriding some
-        // values taken
-        // from the object (e.g. zero PK's).
-        if (currentId != null) {
-            dbDiff.putAll(((ObjectId) currentId).getIdSnapshot());
-        }
-    }
-
-    // ==================================================
-    // GraphChangeHandler methods.
-    // ==================================================
-
-    @Override
-    public void nodePropertyChanged(Object nodeId, String property, Object oldValue, Object newValue) {
-        // note - no checking for phantom mod... assuming there is no phantom
-        // diffs
-
-        if (currentPropertyDiff == null) {
-            currentPropertyDiff = new HashMap<>();
-        }
-
-        currentPropertyDiff.put(property, newValue);
-    }
-
-    @Override
-    public void arcCreated(Object nodeId, Object targetNodeId, ArcId arcId) {
-        String arcIdString = arcId.toString();
-        ObjRelationship relationship = objEntity.getRelationship(arcIdString);
-
-        if (relationship == null) {
-            // phantom FK
-            if (arcIdString.startsWith(ASTDbPath.DB_PREFIX)) {
-                String relName = arcIdString.substring(ASTDbPath.DB_PREFIX.length());
-                DbRelationship dbRelationship = dbEntity.getRelationship(relName);
-                if (!dbRelationship.isSourceIndependentFromTargetChange()) {
-                    doArcCreated(targetNodeId, arcId);
-                }
-            } else {
-                throw new IllegalArgumentException("Bad arcId: " + arcId);
-            }
-
-        } else {
-            if (!relationship.isToMany() && relationship.isToPK()) {
-                doArcCreated(targetNodeId, arcId);
-            }
-        }
-    }
-
-    private void doArcCreated(Object targetNodeId, ArcId arcId) {
-        if (currentArcDiff == null) {
-            currentArcDiff = new HashMap<>();
-        }
-        currentArcDiff.put(arcId, targetNodeId);
-    }
-
-    @Override
-    public void arcDeleted(Object nodeId, Object targetNodeId, ArcId arcId) {
-
-        String arcIdString = arcId.toString();
-        ObjRelationship relationship = objEntity.getRelationship(arcIdString);
-
-        if (relationship == null) {
-            // phantom FK
-            if (arcIdString.startsWith(ASTDbPath.DB_PREFIX)) {
-
-                DbRelationship dbRelationship = dbEntity.getRelationship(arcIdString.substring(ASTDbPath.DB_PREFIX
-                        .length()));
-                if (!dbRelationship.isSourceIndependentFromTargetChange()) {
-                    doArcDeleted(targetNodeId, arcId);
-                }
-            } else {
-                throw new IllegalArgumentException("Bad arcId: " + arcId);
-            }
-
-        } else if (!relationship.isSourceIndependentFromTargetChange()) {
-            doArcDeleted(targetNodeId, arcId);
-        }
-    }
-
-    private void doArcDeleted(Object targetNodeId, ArcId arcId) {
-        if (currentArcDiff == null) {
-            currentArcDiff = new HashMap<>();
-            currentArcDiff.put(arcId, null);
-        } else {
-            // skip deletion record if a substitute arc was created prior to
-            // deleting the old arc...
-            Object existingTargetId = currentArcDiff.get(arcId);
-            if (existingTargetId == null || targetNodeId.equals(existingTargetId)) {
-                currentArcDiff.put(arcId, null);
-            }
-        }
-    }
-
-    @Override
-    public void nodeCreated(Object nodeId) {
-        // need to append PK columns
-        this.currentId = nodeId;
-    }
-
-    @Override
-    public void nodeRemoved(Object nodeId) {
-        // noop
-    }
-
-    @Override
-    public void nodeIdChanged(Object nodeId, Object newId) {
-        // noop
-    }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDeleteBucket.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDeleteBucket.java
deleted file mode 100644
index 755c01b59..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDeleteBucket.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.EntitySorter;
-import org.apache.cayenne.query.DeleteBatchQuery;
-import org.apache.cayenne.query.Query;
-
-/**
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainDeleteBucket extends DataDomainSyncBucket {
-
-    DataDomainDeleteBucket(LegacyDataDomainFlushAction parent) {
-        super(parent);
-    }
-
-    @Override
-    void postprocess() {
-
-        if (!objectsByDescriptor.isEmpty()) {
-
-            Collection<ObjectId> deletedIds = parent.getResultDeletedIds();
-
-            for (List<Persistent> objects : objectsByDescriptor.values()) {
-                for (Persistent object : objects) {
-                    deletedIds.add(object.getObjectId());
-                }
-            }
-        }
-    }
-
-    @Override
-    void appendQueriesInternal(Collection<Query> queries) {
-
-        DataNodeSyncQualifierDescriptor qualifierBuilder = new DataNodeSyncQualifierDescriptor();
-
-        EntitySorter sorter = parent.getDomain().getEntitySorter();
-        sorter.sortDbEntities(dbEntities, true);
-
-        for (DbEntity dbEntity : dbEntities) {
-            Collection<DbEntityClassDescriptor> descriptors = descriptorsByDbEntity
-                    .get(dbEntity);
-            Map<Object, Query> batches = new LinkedHashMap<>();
-
-            for (DbEntityClassDescriptor descriptor : descriptors) {
-
-                qualifierBuilder.reset(descriptor);
-
-                boolean isRootDbEntity = descriptor.isMaster();
-
-                // remove object set for dependent entity, so that it does not show up
-                // on post processing
-                List<Persistent> objects = objectsByDescriptor.get(descriptor
-                        .getClassDescriptor());
-                if (objects.isEmpty()) {
-                    continue;
-                }
-
-                checkReadOnly(descriptor.getEntity());
-
-                if (isRootDbEntity) {
-                    sorter.sortObjectsForEntity(descriptor.getEntity(), objects, true);
-                }
-
-                for (Persistent o : objects) {
-                    ObjectDiff diff = parent.objectDiff(o.getObjectId());
-
-                    Map<String, Object> qualifierSnapshot = qualifierBuilder
-                            .createQualifierSnapshot(diff);
-
-                    // organize batches by the nulls in qualifier
-                    Set<String> nullQualifierNames = new HashSet<String>();
-                    for (Map.Entry<String, ?> entry : qualifierSnapshot.entrySet()) {
-                        if (entry.getValue() == null) {
-                            nullQualifierNames.add(entry.getKey());
-                        }
-                    }
-
-                    Object batchKey = Arrays.asList(nullQualifierNames);
-
-                    DeleteBatchQuery batch = (DeleteBatchQuery) batches.get(batchKey);
-                    if (batch == null) {
-                        batch = new DeleteBatchQuery(dbEntity, qualifierBuilder
-                                .getAttributes(), nullQualifierNames, 27);
-                        batch.setUsingOptimisticLocking(qualifierBuilder
-                                .isUsingOptimisticLocking());
-                        batches.put(batchKey, batch);
-                    }
-
-                    batch.add(qualifierSnapshot);
-                }
-            }
-
-            queries.addAll(batches.values());
-        }
-    }
-}
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
deleted file mode 100644
index 488affd0c..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlattenedBucket.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.query.BatchQueryRow;
-import org.apache.cayenne.query.DeleteBatchQuery;
-import org.apache.cayenne.query.InsertBatchQuery;
-import org.apache.cayenne.query.Query;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A sync bucket that holds flattened queries.
- * 
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainFlattenedBucket {
-
-    final LegacyDataDomainFlushAction parent;
-    final Map<DbEntity, List<FlattenedArcKey>> insertArcKeys;
-    final Map<DbEntity, DeleteBatchQuery> flattenedDeleteQueries;
-
-    DataDomainFlattenedBucket(LegacyDataDomainFlushAction parent) {
-        this.parent = parent;
-        this.insertArcKeys = new HashMap<>();
-        this.flattenedDeleteQueries = new HashMap<>();
-    }
-
-    boolean isEmpty() {
-        return insertArcKeys.isEmpty() && flattenedDeleteQueries.isEmpty();
-    }
-
-    void addInsertArcKey(DbEntity flattenedEntity, FlattenedArcKey flattenedArcKey) {
-        List<FlattenedArcKey> arcKeys = insertArcKeys.get(flattenedEntity);
-
-        if (arcKeys == null) {
-            arcKeys = new ArrayList<>();
-            insertArcKeys.put(flattenedEntity, arcKeys);
-        }
-
-        arcKeys.add(flattenedArcKey);
-    }
-
-    void addFlattenedDelete(DbEntity flattenedEntity, FlattenedArcKey flattenedDeleteInfo) {
-
-        DeleteBatchQuery relationDeleteQuery = flattenedDeleteQueries.get(flattenedEntity);
-        if (relationDeleteQuery == null) {
-            Collection<DbAttribute> pk = flattenedEntity.getPrimaryKeys();
-            List<DbAttribute> pkList = pk instanceof List ? (List<DbAttribute>) pk : new ArrayList<>(pk);
-            relationDeleteQuery = new DeleteBatchQuery(flattenedEntity, pkList, Collections.<String> emptySet(), 50);
-            relationDeleteQuery.setUsingOptimisticLocking(false);
-            flattenedDeleteQueries.put(flattenedEntity, relationDeleteQuery);
-        }
-
-        DataNode node = parent.getDomain().lookupDataNode(flattenedEntity.getDataMap());
-        List<Map<String, Object>> flattenedSnapshots = flattenedDeleteInfo.buildJoinSnapshotsForDelete(node);
-        if (!flattenedSnapshots.isEmpty()) {
-            for (Map<String, Object> flattenedSnapshot : flattenedSnapshots) {
-                relationDeleteQuery.add(flattenedSnapshot);
-            }
-        }
-    }
-
-    /**
-     * responsible for adding the flattened Insert Queries. Its possible an insert query for the same DbEntity/ObjectId
-     * already has been added from the insert bucket queries if that Object also has an attribute. So we want to merge
-     * the data for each insert into a single insert.
-     */
-    void appendInserts(Collection<Query> queries) {
-
-        // TODO: see "O(N) lookups" TODO's below. The first is relatively benign, as N is the number of DbEntities in the
-        // preceeding DataDomainInsertBucket processing. The second nested one is potentially much worse, as it may
-        // result in a linear scan of thousands of objects. E.g. it will affect cases with vertical inheritance with
-        // relationships in subclasses...
-
-        // The fix to the above is to merge this code into DataDomainInsertBucket, so that we can combine regular and
-        // flattened snapshots at the point of InsertBatchQuery creation.
-
-        for (Map.Entry<DbEntity, List<FlattenedArcKey>> entry : insertArcKeys.entrySet()) {
-            DbEntity dbEntity = entry.getKey();
-            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);
-
-            // 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> 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();
-
-                if (existingQuery != null) {
-
-                    // TODO: O(N) lookup
-                    BatchQueryRow existingRow = findRowForObjectId(existingQuery.getRows(), objectId);
-                    // todo: do we need to worry about flattenedArcKey.id2 ?
-
-                    if (existingRow != null) {
-                        List<DbAttribute> existingQueryDbAttributes = existingQuery.getDbAttributes();
-
-                        for(int i=0; i < existingQueryDbAttributes.size(); i++) {
-                            Object value = existingRow.getValue(i);
-                            if (value != null) {
-                                snapshot.put(existingQueryDbAttributes.get(i).getName(), value);
-                            }
-                        }
-                    }
-                }
-
-                newQuery.add(snapshot, objectId);
-            }
-
-            // apply the ToMany snapshots as new BatchQueryRows
-            for(Map<String, Object> toManySnapshot : toManySnapshots) {
-                newQuery.add(toManySnapshot);
-            }
-
-            if (existingQuery != null) {
-                queries.remove(existingQuery);
-            }
-
-            queries.add(newQuery);
-        }
-    }
-
-    void appendDeletes(Collection<Query> queries) {
-        if (!flattenedDeleteQueries.isEmpty()) {
-            queries.addAll(flattenedDeleteQueries.values());
-        }
-    }
-
-    private InsertBatchQuery findInsertBatchQuery(Collection<Query> queries, DbEntity dbEntity) {
-        for(Query query : queries) {
-            if (query instanceof InsertBatchQuery) {
-                InsertBatchQuery insertBatchQuery = (InsertBatchQuery)query;
-                if (insertBatchQuery.getDbEntity().equals(dbEntity)) {
-                    return insertBatchQuery;
-                }
-            }
-        }
-        return null;
-    }
-
-    private BatchQueryRow findRowForObjectId(List<BatchQueryRow> rows, ObjectId objectId) {
-        for (BatchQueryRow row : rows) {
-            if (row.getObjectId().equals(objectId)) {
-                return row;
-            }
-        }
-        return null;
-    }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlushObserver.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlushObserver.java
deleted file mode 100644
index e99a546bf..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainFlushObserver.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.List;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.ResultIterator;
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.query.BatchQuery;
-import org.apache.cayenne.query.InsertBatchQuery;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.util.Util;
-
-/**
- * Used as an observer for DataContext commit operations.
- * 
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainFlushObserver implements OperationObserver {
-
-    /**
-     * @since 3.1
-     */
-    private JdbcEventLogger logger;
-
-    DataDomainFlushObserver(JdbcEventLogger logger) {
-        this.logger = logger;
-    }
-
-    @Override
-    public void nextQueryException(Query query, Exception ex) {
-        throw new CayenneRuntimeException("Raising from query exception.", Util.unwindException(ex));
-    }
-
-    @Override
-    public void nextGlobalException(Exception ex) {
-        throw new CayenneRuntimeException("Raising from underlyingQueryEngine exception.", Util.unwindException(ex));
-    }
-
-    /**
-     * Processes generated keys.
-     * 
-     * @since 1.2
-     */
-    @Override
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    public void nextGeneratedRows(Query query, ResultIterator<?> keysIterator, List<ObjectId> idsToUpdate) {
-
-        // read and close the iterator before doing anything else
-        List<DataRow> keys;
-        try {
-            keys = (List<DataRow>) keysIterator.allRows();
-        } finally {
-            keysIterator.close();
-        }
-
-        if (!(query instanceof InsertBatchQuery)) {
-            throw new CayenneRuntimeException("Generated keys only supported for InsertBatchQuery, instead got %s", query);
-        }
-
-        if (keys.size() != idsToUpdate.size()) {
-            throw new CayenneRuntimeException("Mismatching number of generated PKs: expected %d, instead got %d", idsToUpdate.size(), keys.size());
-        }
-        
-        for (int i = 0; i < keys.size(); i++) {
-	        DataRow key = keys.get(i);
-	
-	        // empty key?
-	        if (key.size() == 0) {
-	            throw new CayenneRuntimeException("Empty key generated.");
-	        }
-	
-	        ObjectId idToUpdate = idsToUpdate.get(i);
-	        if (idToUpdate == null || !idToUpdate.isTemporary()) {
-	            // why would this happen?
-	            return;
-	        }
-
-	        BatchQuery batch = (BatchQuery) query;
-	        for (DbAttribute attribute : batch.getDbEntity().getGeneratedAttributes()) {
-	
-	            // batch can have generated attributes that are not PKs, e.g.
-	            // columns with
-	            // DB DEFAULT values. Ignore those.
-	            if (attribute.isPrimaryKey()) {
-	            	
-	                Object value = key.get(attribute.getName());
-	                
-	    	        // As of now (01/2005) many tested drivers don't provide decent
-	    	        // descriptors of
-	    	        // identity result sets, so a data row may contain garbage labels.
-	                if (value == null) {
-	                	value = key.values().iterator().next();
-	                }
-	                
-	                // Log the generated PK
-	                logger.logGeneratedKey(attribute, value);
-	
-	                // I guess we should override any existing value,
-	                // as generated key is the latest thing that exists in the DB.
-	                idToUpdate.getReplacementIdMap().put(attribute.getName(), value);
-	                break;
-	            }
-	        }
-        }
-    }
-
-    public void setJdbcEventLogger(JdbcEventLogger logger) {
-        this.logger = logger;
-    }
-
-    public JdbcEventLogger getJdbcEventLogger() {
-        return this.logger;
-    }
-
-    @Override
-    public void nextBatchCount(Query query, int[] resultCount) {
-    }
-
-    @Override
-    public void nextCount(Query query, int resultCount) {
-    }
-
-    @Override
-    public void nextRows(Query query, List<?> dataRows) {
-    }
-
-    @Override
-    @SuppressWarnings("rawtypes")
-    public void nextRows(Query q, ResultIterator it) {
-        throw new UnsupportedOperationException(
-                "'nextDataRows(Query,ResultIterator)' is unsupported (and unexpected) on commit.");
-    }
-
-    @Override
-    public boolean isIteratedResult() {
-        return false;
-    }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainIndirectDiffBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainIndirectDiffBuilder.java
deleted file mode 100644
index ae1574e54..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainIndirectDiffBuilder.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.Collection;
-import java.util.HashSet;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.graph.ArcId;
-import org.apache.cayenne.graph.GraphChangeHandler;
-import org.apache.cayenne.graph.GraphDiff;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.EntityResolver;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-
-/**
- * A processor of ObjectStore indirect changes, such as flattened relationships
- * and to-many relationships.
- * 
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-final class DataDomainIndirectDiffBuilder implements GraphChangeHandler {
-
-    private final LegacyDataDomainFlushAction parent;
-    private final EntityResolver resolver;
-    private final Collection<ObjectId> indirectModifications;
-    private final Collection<FlattenedArcKey> flattenedInserts;
-    private final Collection<FlattenedArcKey> flattenedDeletes;
-
-    DataDomainIndirectDiffBuilder(LegacyDataDomainFlushAction parent) {
-        this.parent = parent;
-        this.indirectModifications = parent.getResultIndirectlyModifiedIds();
-        this.resolver = parent.getDomain().getEntityResolver();
-        this.flattenedInserts = new HashSet<>();
-        this.flattenedDeletes = new HashSet<>();
-    }
-
-    void processIndirectChanges(GraphDiff allChanges) {
-        // extract flattened and indirect changes and remove duplicate changes...
-        allChanges.apply(this);
-
-        if (!flattenedInserts.isEmpty()) {
-            for (final FlattenedArcKey key : flattenedInserts) {
-                DbEntity entity = key.getJoinEntity();
-                parent.addFlattenedInsert(entity, key);
-            }
-        }
-
-        if (!flattenedDeletes.isEmpty()) {
-            for (final FlattenedArcKey key : flattenedDeletes) {
-                DbEntity entity = key.getJoinEntity();
-                parent.addFlattenedDelete(entity, key);
-            }
-        }
-    }
-
-    @Override
-    public void arcCreated(Object nodeId, Object targetNodeId, ArcId arcId) {
-        ObjEntity entity = resolver.getObjEntity(((ObjectId) nodeId).getEntityName());
-        ObjRelationship relationship = entity.getRelationship(arcId.toString());
-
-        if (relationship.isSourceIndependentFromTargetChange()) {
-
-            ObjectId nodeObjectId = (ObjectId) nodeId;
-            if (!nodeObjectId.isTemporary()) {
-                indirectModifications.add(nodeObjectId);
-            }
-
-            if (relationship.isFlattened()) {
-                if (relationship.isReadOnly()) {
-                    throw new CayenneRuntimeException("Cannot set the read-only flattened relationship '%s' in ObjEntity '%s'."
-                            , relationship.getName(), relationship.getSourceEntity().getName());
-                }
-
-                // build path without last segment
-                StringBuilder path = new StringBuilder();
-                for(int i=0; i<relationship.getDbRelationships().size() - 1; i++) {
-                    if(path.length() > 0) {
-                        path.append('.');
-                    }
-                    path.append(relationship.getDbRelationships().get(i).getName());
-                }
-
-                if(!parent.getContext().getObjectStore().hasFlattenedPath(nodeObjectId, path.toString())) {
-                    // Register this combination (so we can remove it later if an insert occurs before commit)
-                    FlattenedArcKey key = new FlattenedArcKey(nodeObjectId, (ObjectId) targetNodeId, relationship);
-
-                    // If this combination has already been deleted, simply undelete it.
-                    if (!flattenedDeletes.remove(key)) {
-                        flattenedInserts.add(key);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public void arcDeleted(Object nodeId, Object targetNodeId, ArcId arcId) {
-
-        ObjEntity entity = resolver.getObjEntity(((ObjectId) nodeId).getEntityName());
-        ObjRelationship relationship = entity.getRelationship(arcId.toString());
-
-        if (relationship.isSourceIndependentFromTargetChange()) {
-            // do not record temporary id mods...
-            ObjectId nodeObjectId = (ObjectId) nodeId;
-            if (!nodeObjectId.isTemporary()) {
-                indirectModifications.add(nodeObjectId);
-            }
-
-            if (relationship.isFlattened()) {
-                if (relationship.isReadOnly()) {
-                    throw new CayenneRuntimeException("Cannot unset the read-only flattened relationship %s"
-                            , relationship.getName());
-                }
-
-                // build path without last segment
-                StringBuilder path = new StringBuilder();
-                for(int i=0; i<relationship.getDbRelationships().size() - 1; i++) {
-                    if(path.length() > 0) {
-                        path.append('.');
-                    }
-                    path.append(relationship.getDbRelationships().get(i).getName());
-                }
-
-                if(!parent.getContext().getObjectStore().hasFlattenedPath(nodeObjectId, path.toString())) {
-                    // Register this combination (so we can remove it later if an insert occurs before commit)
-                    FlattenedArcKey key = new FlattenedArcKey(nodeObjectId, (ObjectId) targetNodeId, relationship);
-
-                    // If this combination has already been inserted, simply "uninsert" it also do not delete it twice
-                    if (!flattenedInserts.remove(key)) {
-                        flattenedDeletes.add(key);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public void nodeIdChanged(Object nodeId, Object newId) {
-        // noop
-    }
-
-    @Override
-    public void nodeCreated(Object nodeId) {
-        // noop
-    }
-
-    @Override
-    public void nodeRemoved(Object nodeId) {
-        // noop
-    }
-
-    @Override
-    public void nodePropertyChanged(Object nodeId, String property, Object oldValue, Object newValue) {
-        // noop
-    }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainInsertBucket.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainInsertBucket.java
deleted file mode 100644
index d3b59278f..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainInsertBucket.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.dba.PkGenerator;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.EntitySorter;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.query.InsertBatchQuery;
-import org.apache.cayenne.query.Query;
-
-/**
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainInsertBucket extends DataDomainSyncBucket {
-
-    List<FlattenedInsert> flattenedInserts;
-
-    DataDomainInsertBucket(LegacyDataDomainFlushAction parent) {
-        super(parent);
-    }
-
-    @Override
-    void appendQueriesInternal(Collection<Query> queries) {
-
-        DataDomainDBDiffBuilder diffBuilder = new DataDomainDBDiffBuilder();
-
-        EntitySorter sorter = parent.getDomain().getEntitySorter();
-        sorter.sortDbEntities(dbEntities, false);
-
-        for (DbEntity dbEntity : dbEntities) {
-
-            Collection<DbEntityClassDescriptor> descriptors = descriptorsByDbEntity.get(dbEntity);
-
-            InsertBatchQuery batch = new InsertBatchQuery(dbEntity, 27);
-            for (DbEntityClassDescriptor descriptor : descriptors) {
-
-                diffBuilder.reset(descriptor);
-
-                List<Persistent> objects = objectsByDescriptor.get(descriptor.getClassDescriptor());
-                if (objects.isEmpty()) {
-                    continue;
-                }
-
-                checkReadOnly(descriptor.getEntity());
-                createPermIds(descriptor, objects);
-                sorter.sortObjectsForEntity(descriptor.getEntity(), objects, false);
-
-                for (Persistent o : objects) {
-                    Map<String, Object> snapshot = diffBuilder.buildDBDiff(parent.objectDiff(o.getObjectId()));
-
-                    // we need to insert even if there is no changes to default
-                    // values so creating an empty changes map
-                    if (snapshot == null) {
-                        snapshot = new HashMap<>();
-                    }
-
-                    batch.add(snapshot, o.getObjectId());
-                    if(!descriptor.isMaster()) {
-                        trackFlattenedInsert(descriptor, o);
-                    }
-                }
-            }
-
-            queries.add(batch);
-        }
-    }
-
-    void createPermIds(DbEntityClassDescriptor descriptor, Collection<Persistent> objects) {
-
-        if (objects.isEmpty()) {
-            return;
-        }
-
-        ObjEntity objEntity = descriptor.getEntity();
-        DbEntity entity = descriptor.getDbEntity();
-
-        DataNode node = parent.getDomain().lookupDataNode(entity.getDataMap());
-        boolean supportsGeneratedKeys = node.getAdapter().supportsGeneratedKeys();
-
-        PkGenerator pkGenerator = node.getAdapter().getPkGenerator();
-
-        for (Persistent object : objects) {
-            ObjectId id = object.getObjectId();
-            if (id == null || !id.isTemporary()) {
-                continue;
-            }
-
-            // modify replacement id directly...
-            Map<String, Object> idMap = id.getReplacementIdMap();
-
-            boolean autoPkDone = false;
-
-            for (DbAttribute dbAttr : entity.getPrimaryKeys()) {
-                String dbAttrName = dbAttr.getName();
-
-                if (idMap.containsKey(dbAttrName)) {
-                    continue;
-                }
-
-                // handle meaningful PK
-                ObjAttribute objAttr = objEntity.getAttributeForDbAttribute(dbAttr);
-                if (objAttr != null) {
-
-                    Object value = descriptor.getClassDescriptor().getProperty(objAttr.getName())
-                            .readPropertyDirectly(object);
-
-                    if (value != null) {
-                        Class<?> javaClass = objAttr.getJavaClass();
-                        if (javaClass.isPrimitive() && value instanceof Number && ((Number) value).intValue() == 0) {
-                            // primitive 0 has to be treated as NULL, or
-                            // otherwise we can't generate PK for POJO's
-                        } else {
-                            idMap.put(dbAttrName, value);
-                            continue;
-                        }
-                    }
-                }
-
-                // skip db-generated
-                if (supportsGeneratedKeys && dbAttr.isGenerated()) {
-                    continue;
-                }
-
-                // skip propagated
-                if (isPropagated(dbAttr)) {
-                    continue;
-                }
-
-                // only a single key can be generated from DB... if this is done
-                // already in this loop, we must bail out.
-                if (autoPkDone) {
-                    throw new CayenneRuntimeException("Primary Key autogeneration only works for a single attribute.");
-                }
-
-                // finally, use database generation mechanism
-                try {
-                    Object pkValue = pkGenerator.generatePk(node, dbAttr);
-                    idMap.put(dbAttrName, pkValue);
-                    autoPkDone = true;
-                } catch (Exception ex) {
-                    throw new CayenneRuntimeException("Error generating PK: %s", ex,  ex.getMessage());
-                }
-            }
-        }
-    }
-
-    // TODO, andrus 4/12/2006 - move to DbAttribute in 2.0+
-    boolean isPropagated(DbAttribute attribute) {
-
-        for (DbRelationship dbRel : attribute.getEntity().getRelationships()) {
-            if (!dbRel.isToMasterPK()) {
-                continue;
-            }
-
-            for (DbJoin join : dbRel.getJoins()) {
-                if (attribute.getName().equals(join.getSourceName())) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    void trackFlattenedInsert(DbEntityClassDescriptor descriptor, Persistent object) {
-        if(flattenedInserts == null) {
-            flattenedInserts = new LinkedList<>();
-        }
-
-        StringBuilder sb = new StringBuilder();
-        for(DbRelationship rel : descriptor.getPathFromMaster()) {
-            if(sb.length() > 0) {
-                sb.append('.');
-            }
-            sb.append(rel.getName());
-         }
-
-        flattenedInserts.add(new FlattenedInsert(sb.toString(), object));
-    }
-
-    @Override
-    void postprocess() {
-        super.postprocess();
-        if(flattenedInserts != null) {
-            for(FlattenedInsert insert : flattenedInserts) {
-                insert.register(parent.getContext().getObjectStore());
-            }
-        }
-    }
-
-    private static class FlattenedInsert {
-        private final String path;
-        private final Persistent object;
-
-        private FlattenedInsert(String path, Persistent object) {
-            this.path = path;
-            this.object = object;
-        }
-
-        private void register(ObjectStore objectStore) {
-            objectStore.markFlattenedPath(object.getObjectId(), path, ObjectId.of("tmp"));
-        }
-    }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainSyncBucket.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainSyncBucket.java
deleted file mode 100644
index 23dc5c295..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainSyncBucket.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.DataObject;
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.graph.CompoundDiff;
-import org.apache.cayenne.graph.NodeIdChangeOperation;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.reflect.ArcProperty;
-import org.apache.cayenne.reflect.AttributeProperty;
-import org.apache.cayenne.reflect.ClassDescriptor;
-import org.apache.cayenne.reflect.PropertyException;
-import org.apache.cayenne.reflect.ToManyMapProperty;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Supplier;
-
-/**
- * A superclass of batch query wrappers.
- * 
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-abstract class DataDomainSyncBucket {
-
-    final Map<ClassDescriptor, List<Persistent>> objectsByDescriptor;
-    final LegacyDataDomainFlushAction parent;
-
-    List<DbEntity> dbEntities;
-    Map<DbEntity, Collection<DbEntityClassDescriptor>> descriptorsByDbEntity;
-
-    DataDomainSyncBucket(LegacyDataDomainFlushAction parent) {
-        this.objectsByDescriptor = new HashMap<>();
-        this.parent = parent;
-    }
-
-    boolean isEmpty() {
-        return objectsByDescriptor.isEmpty();
-    }
-
-    abstract void appendQueriesInternal(Collection<Query> queries);
-
-    /**
-     * Appends all queries originated in the bucket to provided collection.
-     */
-    void appendQueries(Collection<Query> queries) {
-
-        if (!objectsByDescriptor.isEmpty()) {
-            groupObjEntitiesBySpannedDbEntities();
-            appendQueriesInternal(queries);
-        }
-    }
-
-    void checkReadOnly(ObjEntity entity) throws CayenneRuntimeException {
-
-        if (entity == null) {
-            throw new NullPointerException("Entity must not be null.");
-        }
-
-        if (entity.isReadOnly()) {
-            throw new CayenneRuntimeException("Attempt to modify object(s) mapped to a read-only entity: '%s'. " +
-                    "Can't commit changes.", entity.getName());
-        }
-    }
-
-    private void groupObjEntitiesBySpannedDbEntities() {
-
-        dbEntities = new ArrayList<>(objectsByDescriptor.size());
-        descriptorsByDbEntity = new HashMap<>(objectsByDescriptor.size() * 2);
-
-        for (ClassDescriptor descriptor : objectsByDescriptor.keySet()) {
-            addSpannedDbEntities(descriptor);
-        }
-    }
-
-    void addSpannedDbEntities(ClassDescriptor descriptor) {
-        // root DbEntity
-        addDescriptor(descriptor, new DbEntityClassDescriptor(descriptor));
-
-        // secondary DbEntities...
-        // Note that this logic won't allow flattened attributes to span multiple databases...
-        for (ObjAttribute objAttribute : descriptor.getEntity().getAttributes()) {
-            if (objAttribute.isFlattened()) {
-                addDescriptor(descriptor, new DbEntityClassDescriptor(descriptor, objAttribute));
-            }
-        }
-    }
-
-    void addDescriptor(ClassDescriptor descriptor, DbEntityClassDescriptor dbEntityDescriptor) {
-        DbEntity dbEntity = dbEntityDescriptor.getDbEntity();
-        Collection<DbEntityClassDescriptor> descriptors = descriptorsByDbEntity.get(dbEntity);
-
-        if (descriptors == null) {
-            descriptors = new ArrayList<>(1);
-            dbEntities.add(dbEntity);
-            descriptorsByDbEntity.put(dbEntity, descriptors);
-        }
-
-        if (!containsClassDescriptor(descriptors, descriptor)) {
-            descriptors.add(dbEntityDescriptor);
-        }
-    }
-
-    private boolean containsClassDescriptor(
-            Collection<DbEntityClassDescriptor> descriptors,
-            ClassDescriptor classDescriptor) {
-        for (DbEntityClassDescriptor descriptor : descriptors) {
-            if (classDescriptor.equals(descriptor.getClassDescriptor())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    void addDirtyObject(Persistent object, ClassDescriptor descriptor) {
-        objectsByDescriptor.computeIfAbsent(descriptor, k -> new ArrayList<>()).add(object);
-    }
-
-    void postprocess() {
-
-        if (!objectsByDescriptor.isEmpty()) {
-
-            CompoundDiff result = parent.getResultDiff();
-            Map<ObjectId, DataRow> modifiedSnapshots = parent
-                    .getResultModifiedSnapshots();
-            Collection<ObjectId> deletedIds = parent.getResultDeletedIds();
-
-            for (Map.Entry<ClassDescriptor, List<Persistent>> entry : objectsByDescriptor.entrySet()) {
-
-                ClassDescriptor descriptor = entry.getKey();
-
-                for (Persistent object : entry.getValue()) {
-                    ObjectId id = object.getObjectId();
-
-                    ObjectId finalId;
-
-                    // record id change and update attributes for generated ids
-                    if (id.isReplacementIdAttached()) {
-
-                        Map<String, Object> replacement = id.getReplacementIdMap();
-                        for (AttributeProperty property : descriptor.getIdProperties()) {
-
-                            Object value = replacement.get(property
-                                    .getAttribute()
-                                    .getDbAttributeName());
-
-                            // TODO: andrus, 11/28/2006: this operation may be redundant
-                            // if the id wasn't generated. We may need to optimize it...
-                            if (value != null) {
-                                property.writePropertyDirectly(object, null, value);
-                            }
-                        }
-
-                        ObjectId replacementId = id.createReplacementId();
-
-                        result.add(new NodeIdChangeOperation(id, replacementId));
-
-                        // classify replaced permanent ids as "deleted", as
-                        // DataRowCache has no notion of replaced id...
-                        if (!id.isTemporary()) {
-                            deletedIds.add(id);
-                        }
-
-                        finalId = replacementId;
-                    } else if (id.isTemporary()) {
-                        throw new CayenneRuntimeException("Temporary ID hasn't been replaced on commit: %s", object);
-                    } else {
-                        finalId = id;
-                    }
-
-                    // do not take the snapshot until generated columns are processed (see code above)
-                    DataRow dataRow = parent.getContext().currentSnapshot(object);
-
-                    if (object instanceof DataObject) {
-                        DataObject dataObject = (DataObject) object;
-                        dataRow.setReplacesVersion(dataObject.getSnapshotVersion());
-                        dataObject.setSnapshotVersion(dataRow.getVersion());
-                    }
-
-                    modifiedSnapshots.put(finalId, dataRow);
-
-                    // update Map reverse relationships
-                    for (ArcProperty arc : descriptor.getMapArcProperties()) {
-                        ToManyMapProperty reverseArc = (ToManyMapProperty) arc.getComplimentaryReverseArc();
-
-                        // must resolve faults... hopefully for to-one this will not cause extra fetches...
-                        Object source = arc.readProperty(object);
-                        if (source != null && !reverseArc.isFault(source)) {
-                            remapTarget(reverseArc, source, object);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private void remapTarget(
-            ToManyMapProperty property,
-            Object source,
-            Object target) throws PropertyException {
-
-        Map<Object, Object> map = (Map<Object, Object>) property.readProperty(source);
-        Object newKey = property.getMapKey(target);
-        Object currentValue = map.get(newKey);
-
-        if (currentValue == target) {
-            // nothing to do
-            return;
-        }
-        // else - do not check for conflicts here (i.e. another object mapped for the same
-        // key), as we have no control of the order in which this method is called, so
-        // another object may be remapped later by the caller
-
-        // must do a slow map scan to ensure the object is not mapped under a different key...
-        Iterator<Map.Entry<Object, Object>> it = map.entrySet().iterator();
-        while (it.hasNext()) {
-            Map.Entry<Object, Object> e = it.next();
-            if (e.getValue() == target) {
-                it.remove();
-                break;
-            }
-        }
-
-        map.put(newKey, target);
-    }
-
-    // a factory for extracting PKs generated on commit.
-    final static class PropagatedValueFactory implements Supplier {
-
-        ObjectId masterID;
-        String masterKey;
-
-        PropagatedValueFactory(ObjectId masterID, String masterKey) {
-            this.masterID = masterID;
-            this.masterKey = masterKey;
-        }
-
-        public Object get() {
-            Object value = masterID.getIdSnapshot().get(masterKey);
-            if (value == null) {
-                throw new CayenneRuntimeException("Can't extract a master key. "
-                        + "Missing key (%s), master ID (%s)", masterKey, masterID);
-            }
-
-            return value;
-        }
-    }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainUpdateBucket.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainUpdateBucket.java
deleted file mode 100644
index 55d426ca6..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainUpdateBucket.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.map.Attribute;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.query.UpdateBatchQuery;
-import org.apache.cayenne.reflect.ClassDescriptor;
-
-/**
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataDomainUpdateBucket extends DataDomainSyncBucket {
-
-    DataDomainUpdateBucket(LegacyDataDomainFlushAction parent) {
-        super(parent);
-    }
-
-    @Override
-    void addSpannedDbEntities(ClassDescriptor descriptor) {
-        super.addSpannedDbEntities(descriptor);
-        // for update we need to add entities for flattened toOne relationships
-        for(ObjRelationship objRelationship : descriptor.getEntity().getRelationships()) {
-            if(objRelationship.isFlattened() && !objRelationship.isToMany()) {
-                addDescriptor(descriptor, new DbEntityClassDescriptor(descriptor, objRelationship));
-            }
-        }
-    }
-
-    @Override
-    void appendQueriesInternal(Collection<Query> queries) {
-
-        DataDomainDBDiffBuilder diffBuilder = new DataDomainDBDiffBuilder();
-        DataNodeSyncQualifierDescriptor qualifierBuilder = new DataNodeSyncQualifierDescriptor();
-
-        for (DbEntity dbEntity : dbEntities) {
-
-            Collection<DbEntityClassDescriptor> descriptors = descriptorsByDbEntity.get(dbEntity);
-            Map<Object, Query> batches = new LinkedHashMap<>();
-
-            for (DbEntityClassDescriptor descriptor : descriptors) {
-                ObjEntity entity = descriptor.getEntity();
-
-                diffBuilder.reset(descriptor);
-                qualifierBuilder.reset(descriptor);
-                boolean isRootDbEntity = entity.getDbEntity() == dbEntity;
-
-                for (Persistent o : objectsByDescriptor.get(descriptor.getClassDescriptor())) {
-                    ObjectDiff diff = parent.objectDiff(o.getObjectId());
-
-                    Map<String, Object> snapshot = diffBuilder.buildDBDiff(diff);
-
-                    // check whether MODIFIED object has real db-level modifications
-                    if (snapshot == null) {
-                        continue;
-                    }
-
-                    // after we filtered out "fake" modifications, check if an
-                    // attempt is made to modify a read only entity
-                    checkReadOnly(entity);
-
-                    Map<String, Object> qualifierSnapshot = qualifierBuilder.createQualifierSnapshot(diff);
-
-                    // organize batches by the updated columns + nulls in qualifier
-                    Set<String> snapshotSet = snapshot.keySet();
-                    Set<String> nullQualifierNames = new HashSet<>();
-                    for (Map.Entry<String, Object> entry : qualifierSnapshot.entrySet()) {
-                        if (entry.getValue() == null) {
-                            nullQualifierNames.add(entry.getKey());
-                        }
-                    }
-
-                    List<Set<String>> batchKey = Arrays.asList(snapshotSet, nullQualifierNames);
-
-                    UpdateBatchQuery batch = (UpdateBatchQuery) batches.get(batchKey);
-                    if (batch == null) {
-                        batch = new UpdateBatchQuery(
-                                dbEntity,
-                                qualifierBuilder.getAttributes(),
-                                updatedAttributes(dbEntity, snapshot),
-                                nullQualifierNames,
-                                10);
-
-                        batch.setUsingOptimisticLocking(qualifierBuilder.isUsingOptimisticLocking());
-                        batches.put(batchKey, batch);
-                    }
-
-                    batch.add(qualifierSnapshot, snapshot, o.getObjectId());
-
-                    // update replacement id with meaningful PK changes
-                    if (isRootDbEntity) {
-                        Map<String, Object> replacementId = o
-                                .getObjectId()
-                                .getReplacementIdMap();
-
-                        for (DbAttribute pk : dbEntity.getPrimaryKeys()) {
-                            String name = pk.getName();
-                            if (snapshot.containsKey(name)
-                                    && !replacementId.containsKey(name)) {
-                                replacementId.put(name, snapshot.get(name));
-                            }
-                        }
-                    }
-                }
-            }
-
-            queries.addAll(batches.values());
-        }
-    }
-
-    /**
-     * Creates a list of DbAttributes that are updated in a snapshot
-     */
-    private List<DbAttribute> updatedAttributes(DbEntity entity, Map<String, Object> updatedSnapshot) {
-        List<DbAttribute> attributes = new ArrayList<>(updatedSnapshot.size());
-        Map<String, ? extends Attribute> entityAttributes = entity.getAttributeMap();
-
-        for (String name : updatedSnapshot.keySet()) {
-            attributes.add((DbAttribute)entityAttributes.get(name));
-        }
-
-        return attributes;
-    }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataNodeSyncQualifierDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataNodeSyncQualifierDescriptor.java
deleted file mode 100644
index 49c225b03..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataNodeSyncQualifierDescriptor.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-
-/**
- * Builds update qualifier snapshots, including optimistic locking.
- * 
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DataNodeSyncQualifierDescriptor {
-
-	private List<DbAttribute> attributes;
-	private List<Function<ObjectDiff, Object>> valueTransformers;
-	private boolean usingOptimisticLocking;
-
-	public boolean isUsingOptimisticLocking() {
-		return usingOptimisticLocking;
-	}
-
-	List<DbAttribute> getAttributes() {
-		return attributes;
-	}
-
-	Map<String, Object> createQualifierSnapshot(ObjectDiff diff) {
-		int len = attributes.size();
-
-		Map<String, Object> map = new HashMap<>(len * 2);
-		for (int i = 0; i < len; i++) {
-			DbAttribute attribute = attributes.get(i);
-			if (!map.containsKey(attribute.getName())) {
-				Object value = valueTransformers.get(i).apply(diff);
-				map.put(attribute.getName(), value);
-			}
-		}
-
-		return map;
-	}
-
-	void reset(DbEntityClassDescriptor descriptor) {
-
-		attributes = new ArrayList<>(3);
-		valueTransformers = new ArrayList<>(3);
-		usingOptimisticLocking = descriptor.getEntity().getLockType() == ObjEntity.LOCK_TYPE_OPTIMISTIC;
-
-		// master PK columns
-		if (descriptor.isMaster()) {
-			for (final DbAttribute attribute : descriptor.getDbEntity().getPrimaryKeys()) {
-				attributes.add(attribute);
-				valueTransformers.add(input -> {
-                    ObjectId id = (ObjectId) input.getNodeId();
-                    return id.getIdSnapshot().get(attribute.getName());
-                });
-			}
-		} else {
-
-			// TODO: andrus 12/23/2007 - only one step relationship is supported...
-			if (descriptor.getPathFromMaster().size() != 1) {
-				throw new CayenneRuntimeException(
-				        "Only single step dependent relationships are currently supported. Actual path length: %d"
-                        , descriptor.getPathFromMaster().size());
-			}
-
-			DbRelationship masterDependentDbRel = descriptor.getPathFromMaster().get(0);
-
-			if (masterDependentDbRel != null) {
-				for (final DbJoin dbAttrPair : masterDependentDbRel.getJoins()) {
-					DbAttribute dbAttribute = dbAttrPair.getTarget();
-					if (!attributes.contains(dbAttribute)) {
-
-						attributes.add(dbAttribute);
-						valueTransformers.add(input -> {
-                            ObjectId id = (ObjectId) input.getNodeId();
-                            return id.getIdSnapshot().get(dbAttrPair.getTargetName());
-                        });
-                    }
-                }
-            }
-        }
-
-		if (descriptor.isMaster() && usingOptimisticLocking) {
-
-			for (final ObjAttribute attribute : descriptor.getEntity().getAttributes()) {
-
-				if (attribute.isUsedForLocking() && !attribute.isFlattened()) {
-					// only care about first step in a flattened attribute
-					DbAttribute dbAttribute = (DbAttribute) attribute.getDbPathIterator().next();
-
-					// only use qualifier if dbEntities match
-					if (dbAttribute.getEntity().equals(descriptor.getDbEntity()) && !attributes.contains(dbAttribute)) {
-						attributes.add(dbAttribute);
-						valueTransformers.add(input -> input.getSnapshotValue(attribute.getName()));
-					}
-				}
-			}
-
-			for (final ObjRelationship relationship : descriptor.getEntity().getRelationships()) {
-
-				if (relationship.isUsedForLocking()) {
-					// only care about the first DbRelationship
-					DbRelationship dbRelationship = relationship.getDbRelationships().get(0);
-
-					for (final DbJoin dbAttrPair : dbRelationship.getJoins()) {
-						DbAttribute dbAttribute = dbAttrPair.getSource();
-
-						// relationship transformers override attribute transformers for meaningful FK's...
-						// why meaningful FKs can go out of sync is another story (CAY-595)
-						int index = attributes.indexOf(dbAttribute);
-						if (index >= 0 && !dbAttribute.isForeignKey()) {
-							continue;
-						}
-
-						Function<ObjectDiff, Object> transformer = input -> {
-                            ObjectId targetId = input.getArcSnapshotValue(relationship.getName());
-                            return targetId != null ? targetId.getIdSnapshot().get(dbAttrPair.getTargetName()) : null;
-                        };
-
-						if (index < 0) {
-							attributes.add(dbAttribute);
-							valueTransformers.add(transformer);
-						} else {
-							valueTransformers.set(index, transformer);
-						}
-					}
-				}
-			}
-		}
-	}
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DbArcId.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DbArcId.java
deleted file mode 100644
index a18626f8d..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DbArcId.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.util.EqualsBuilder;
-import org.apache.cayenne.util.HashCodeBuilder;
-
-/**
- * An id similar to ObjectId that identifies a DbEntity snapshot for implicit
- * DbEntities of flattened attributes or relationships. Provides 'equals' and
- * 'hashCode' implementations adequate for use as a map key.
- * 
- * @since 4.0
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-final class DbArcId {
-
-    private int hashCode;
-
-    private ObjectId sourceId;
-    private DbRelationship incomingArc;
-
-    private DbEntity entity;
-
-    DbArcId(ObjectId sourceId, DbRelationship incomingArc) {
-        this.sourceId = sourceId;
-        this.incomingArc = incomingArc;
-    }
-
-    DbEntity getEntity() {
-        if (entity == null) {
-            entity = (DbEntity) incomingArc.getTargetEntity();
-        }
-
-        return entity;
-    }
-
-    ObjectId getSourceId() {
-        return sourceId;
-    }
-
-    DbRelationship getIncominArc() {
-        return incomingArc;
-    }
-
-    @Override
-    public int hashCode() {
-
-        if (this.hashCode == 0) {
-            HashCodeBuilder builder = new HashCodeBuilder(3, 5);
-            builder.append(sourceId);
-            builder.append(incomingArc.getName());
-            this.hashCode = builder.toHashCode();
-        }
-
-        return hashCode;
-    }
-
-    @Override
-    public boolean equals(Object object) {
-
-        if (this == object) {
-            return true;
-        }
-
-        if (!(object instanceof DbArcId)) {
-            return false;
-        }
-
-        DbArcId id = (DbArcId) object;
-
-        return new EqualsBuilder().append(sourceId, id.sourceId)
-                .append(incomingArc.getName(), id.incomingArc.getName())
-                .isEquals();
-    }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DbEntityClassDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DbEntityClassDescriptor.java
deleted file mode 100644
index 496a968bf..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DbEntityClassDescriptor.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.reflect.ClassDescriptor;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * A descriptor of a primary or secondary DbEntity for a given persistent class during
- * commit.
- * 
- * @since 3.0
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-class DbEntityClassDescriptor {
-
-    private ClassDescriptor classDescriptor;
-    private List<DbRelationship> pathFromMaster;
-    private DbEntity dbEntity;
-
-    DbEntityClassDescriptor(ClassDescriptor classDescriptor) {
-        this.classDescriptor = classDescriptor;
-        this.dbEntity = classDescriptor.getEntity().getDbEntity();
-    }
-
-    DbEntityClassDescriptor(ClassDescriptor classDescriptor, ObjAttribute masterAttribute) {
-        this.classDescriptor = classDescriptor;
-
-        Iterator<?> it = masterAttribute.getDbPathIterator();
-
-        if (masterAttribute.isFlattened()) {
-
-            while (it.hasNext()) {
-                Object object = it.next();
-                if (object instanceof DbRelationship) {
-
-                    if (pathFromMaster == null) {
-                        pathFromMaster = new ArrayList<>(1);
-                    }
-
-                    pathFromMaster.add((DbRelationship) object);
-                }
-                else if (object instanceof DbAttribute) {
-                    this.dbEntity = ((DbAttribute) object).getEntity();
-                }
-            }
-        }
-
-        if (dbEntity == null) {
-            dbEntity = classDescriptor.getEntity().getDbEntity();
-        }
-    }
-
-    DbEntityClassDescriptor(ClassDescriptor classDescriptor, ObjRelationship masterRelationship) {
-        if(masterRelationship.getDbRelationships().size() > 2) {
-            throw new CayenneRuntimeException("Only two step flattened relationships are supported, " + masterRelationship.getDbRelationshipPath());
-        }
-        this.classDescriptor = classDescriptor;
-        DbRelationship pathRelationship = masterRelationship.getDbRelationships().get(0);
-        pathFromMaster = new ArrayList<>(1);
-        pathFromMaster.add(pathRelationship);
-        dbEntity = pathRelationship.getTargetEntity();
-    }
-
-    boolean isMaster() {
-        return pathFromMaster == null;
-    }
-
-    ClassDescriptor getClassDescriptor() {
-        return classDescriptor;
-    }
-
-    List<DbRelationship> getPathFromMaster() {
-        return pathFromMaster;
-    }
-
-    DbEntity getDbEntity() {
-        return dbEntity;
-    }
-
-    ObjEntity getEntity() {
-        return classDescriptor.getEntity();
-    }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/FlattenedArcKey.java b/cayenne-server/src/main/java/org/apache/cayenne/access/FlattenedArcKey.java
deleted file mode 100644
index 64e410c1d..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/FlattenedArcKey.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.access.DataDomainSyncBucket.PropagatedValueFactory;
-import org.apache.cayenne.access.util.DefaultOperationObserver;
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.dba.QuotingStrategy;
-import org.apache.cayenne.dba.TypesMapping;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.util.HashCodeBuilder;
-import org.apache.cayenne.util.Util;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A holder of flattened relationship modification data.
- * 
- * @since 1.2
- * @deprecated since 4.2 as part of deprecated {@link LegacyDataDomainFlushAction}
- */
-@Deprecated
-final class FlattenedArcKey {
-
-	ObjRelationship relationship;
-
-	DbArcId id1;
-	DbArcId id2;
-
-	FlattenedArcKey(ObjectId sourceId, ObjectId destinationId, ObjRelationship relationship) {
-
-		this.relationship = relationship;
-
-		List<DbRelationship> dbRelationships = relationship.getDbRelationships();
-		if (dbRelationships.size() != 2) {
-			throw new CayenneRuntimeException(
-					"Only single-step flattened relationships are supported in this operation, whereas the relationship '%s' has %s",
-					relationship, dbRelationships.size());
-		}
-
-		DbRelationship r1 = dbRelationships.get(0);
-		DbRelationship r2 = dbRelationships.get(1).getReverseRelationship();
-
-		if (r2 == null) {
-			throw new IllegalStateException("No reverse relationship for DbRelationship " + dbRelationships.get(1));
-		}
-
-		id1 = new DbArcId(sourceId, r1);
-		id2 = new DbArcId(destinationId, r2);
-	}
-
-	/**
-	 * Returns a join DbEntity for the single-step flattened relationship.
-	 */
-	DbEntity getJoinEntity() {
-		return id1.getEntity();
-	}
-
-	/**
-	 * Returns a snapshot for join record for the single-step flattened
-	 * relationship, generating value for the primary key column if it is not
-	 * propagated via the relationships.
-	 */
-	Map<String, Object> buildJoinSnapshotForInsert(DataNode node) {
-		Map<String, Object> snapshot = lazyJoinSnapshot();
-
-		boolean autoPkDone = false;
-		DbEntity joinEntity = getJoinEntity();
-
-		for (DbAttribute dbAttr : joinEntity.getPrimaryKeys()) {
-			String dbAttrName = dbAttr.getName();
-			if (snapshot.containsKey(dbAttrName)) {
-				continue;
-			}
-
-			DbAdapter adapter = node.getAdapter();
-
-			// skip db-generated... looks like we don't care about the actual PK
-			// value here, so no need to retrieve db-generated pk back to Java.
-			if (adapter.supportsGeneratedKeys() && dbAttr.isGenerated()) {
-				continue;
-			}
-
-			if (autoPkDone) {
-				throw new CayenneRuntimeException("Primary Key autogeneration only works for a single attribute.");
-			}
-
-			// finally, use database generation mechanism
-			try {
-				Object pkValue = adapter.getPkGenerator().generatePk(node, dbAttr);
-				snapshot.put(dbAttrName, pkValue);
-				autoPkDone = true;
-			} catch (Exception ex) {
-				throw new CayenneRuntimeException("Error generating PK: %s", ex,  ex.getMessage());
-			}
-		}
-
-		return snapshot;
-	}
-
-	/**
-	 * Returns pk snapshots for join records for the single-step flattened
-	 * relationship. Multiple joins between the same pair of objects are
-	 * theoretically possible, so the return value is a list.
-	 */
-	List buildJoinSnapshotsForDelete(DataNode node) {
-		Map<String, Object> snapshot = eagerJoinSnapshot();
-
-		DbEntity joinEntity = getJoinEntity();
-
-		boolean fetchKey = false;
-		for (DbAttribute dbAttr : joinEntity.getPrimaryKeys()) {
-			String dbAttrName = dbAttr.getName();
-			if (!snapshot.containsKey(dbAttrName)) {
-				fetchKey = true;
-				break;
-			}
-		}
-
-		if (!fetchKey) {
-			return Collections.singletonList(snapshot);
-		}
-
-		// ok, the key is not included in snapshot, must do the fetch...
-		// TODO: this should be optimized in the future, but now
-		// DeleteBatchQuery
-		// expects a PK snapshot, so we must provide it.
-
-		QuotingStrategy quoter = node.getAdapter().getQuotingStrategy();
-
-		StringBuilder sql = new StringBuilder("SELECT ");
-		Collection<DbAttribute> pk = joinEntity.getPrimaryKeys();
-		final List<DbAttribute> pkList = pk instanceof List ? (List<DbAttribute>) pk : new ArrayList<>(pk);
-
-		for (int i = 0; i < pkList.size(); i++) {
-
-			if (i > 0) {
-				sql.append(", ");
-			}
-
-			DbAttribute attribute = pkList.get(i);
-
-			sql.append("#result('");
-			sql.append(quoter.quotedName(attribute));
-
-			// since the name of the column can potentially be quoted and
-			// use reserved keywords as name, let's specify generated column
-			// name parameters to ensure the query doesn't explode
-			sql.append("' '").append(TypesMapping.getJavaBySqlType(attribute));
-			sql.append("' '").append("pk").append(i);
-			sql.append("')");
-		}
-
-		sql.append(" FROM ").append(quoter.quotedFullyQualifiedName(joinEntity)).append(" WHERE ");
-		int i = snapshot.size();
-		for (Object key : snapshot.keySet()) {
-			sql.append(quoter.quotedIdentifier(joinEntity, String.valueOf(key))).append(" #bindEqual($").append(key)
-					.append(")");
-
-			if (--i > 0) {
-				sql.append(" AND ");
-			}
-		}
-
-		SQLTemplate query = new SQLTemplate(joinEntity.getDataMap(), sql.toString(), true);
-		query.setParams(snapshot);
-
-		final List[] result = new List[1];
-
-		node.performQueries(Collections.singleton((Query) query), new DefaultOperationObserver() {
-
-			@Override
-			public void nextRows(Query query, List<?> dataRows) {
-
-				if (!dataRows.isEmpty()) {
-					// decode results...
-
-					List<DataRow> fixedRows = new ArrayList<>(dataRows.size());
-					for (Object o : dataRows) {
-						DataRow row = (DataRow) o;
-
-						DataRow fixedRow = new DataRow(2);
-
-						for (int i = 0; i < pkList.size(); i++) {
-							DbAttribute attribute = pkList.get(i);
-							fixedRow.put(attribute.getName(), row.get("pk" + i));
-						}
-
-						fixedRows.add(fixedRow);
-					}
-
-					dataRows = fixedRows;
-				}
-
-				result[0] = dataRows;
-			}
-
-			@Override
-			public void nextQueryException(Query query, Exception ex) {
-				throw new CayenneRuntimeException("Raising from query exception.", Util.unwindException(ex));
-			}
-
-			@Override
-			public void nextGlobalException(Exception ex) {
-				throw new CayenneRuntimeException("Raising from underlyingQueryEngine exception.", Util
-						.unwindException(ex));
-			}
-		});
-
-		return result[0];
-	}
-
-	@Override
-	public int hashCode() {
-		// order ids in array for hashcode consistency purposes. The actual
-		// order direction is not important, as long as it
-		// is consistent across invocations
-
-		int compare = id1.getSourceId().getEntityName().compareTo(id2.getSourceId().getEntityName());
-
-		if (compare == 0) {
-			compare = id1.getIncominArc().getName().compareTo(id2.getIncominArc().getName());
-
-			if (compare == 0) {
-				// since ordering is mostly important for detecting equivalent
-				// FlattenedArc keys coming from 2 opposite directions, the name
-				// of ObjRelationship can be a good criteria
-
-				ObjRelationship or2 = relationship.getReverseRelationship();
-				compare = or2 != null ? relationship.getName().compareTo(or2.getName()) : 1;
-
-				// TODO: if(compare == 0) ??
-			}
-		}
-
-		DbArcId[] ordered;
-		if (compare < 0) {
-			ordered = new DbArcId[] { id1, id2 };
-		} else {
-			ordered = new DbArcId[] { id2, id1 };
-		}
-
-		return new HashCodeBuilder().append(ordered).toHashCode();
-	}
-
-	/**
-	 * Defines equal based on whether the relationship is bidirectional.
-	 */
-	@Override
-	public boolean equals(Object object) {
-
-		if (this == object) {
-			return true;
-		}
-
-		if (!(object instanceof FlattenedArcKey)) {
-			return false;
-		}
-
-		FlattenedArcKey key = (FlattenedArcKey) object;
-
-		// ignore id order in comparison
-		if (id1.equals(key.id1)) {
-			return id2.equals(key.id2);
-		} else if (id1.equals(key.id2)) {
-			return id2.equals(key.id1);
-		}
-
-		return false;
-	}
-
-	private Map<String, Object> eagerJoinSnapshot() {
-
-		List<DbRelationship> relList = relationship.getDbRelationships();
-		if (relList.size() != 2) {
-			throw new CayenneRuntimeException(
-					"Only single-step flattened relationships are supported in this operation: %s", relationship);
-		}
-
-		DbRelationship firstDbRel = relList.get(0);
-		DbRelationship secondDbRel = relList.get(1);
-
-		// here ordering of ids is determined by 'relationship', so use id1, id2
-		// instead of orderedIds
-		Map<String, ?> sourceId = id1.getSourceId().getIdSnapshot();
-		Map<String, ?> destinationId = id2.getSourceId().getIdSnapshot();
-
-		Map<String, Object> snapshot = new HashMap<>(sourceId.size() + destinationId.size(), 1);
-		for (DbJoin join : firstDbRel.getJoins()) {
-			snapshot.put(join.getTargetName(), sourceId.get(join.getSourceName()));
-		}
-
-		for (DbJoin join : secondDbRel.getJoins()) {
-			snapshot.put(join.getSourceName(), destinationId.get(join.getTargetName()));
-		}
-
-		return snapshot;
-	}
-
-	private Map<String, Object> lazyJoinSnapshot() {
-
-		List<DbRelationship> relList = relationship.getDbRelationships();
-		if (relList.size() != 2) {
-			throw new CayenneRuntimeException(
-					"Only single-step flattened relationships are supported in this operation: %s", relationship);
-		}
-
-		DbRelationship firstDbRel = relList.get(0);
-		DbRelationship secondDbRel = relList.get(1);
-
-		List<DbJoin> fromSourceJoins = firstDbRel.getJoins();
-		List<DbJoin> toTargetJoins = secondDbRel.getJoins();
-
-		Map<String, Object> snapshot = new HashMap<>(fromSourceJoins.size() + toTargetJoins.size(), 1);
-
-		// here ordering of ids is determined by 'relationship', so use id1, id2
-		// instead of orderedIds
-
-		for (DbJoin join : fromSourceJoins) {
-			Object value = new PropagatedValueFactory(id1.getSourceId(), join.getSourceName());
-			snapshot.put(join.getTargetName(), value);
-		}
-
-		for (DbJoin join : toTargetJoins) {
-			Object value = new PropagatedValueFactory(id2.getSourceId(), join.getTargetName());
-			snapshot.put(join.getSourceName(), value);
-		}
-
-		return snapshot;
-	}
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushAction.java b/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushAction.java
deleted file mode 100644
index a461f1393..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushAction.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.PersistenceState;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.access.flush.DefaultDataDomainFlushAction;
-import org.apache.cayenne.graph.CompoundDiff;
-import org.apache.cayenne.graph.GraphDiff;
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.query.BatchQuery;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.reflect.ClassDescriptor;
-import org.apache.cayenne.tx.BaseTransaction;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A stateful commit handler used by DataContext to perform commit operation.
- * DataContextCommitAction resolves primary key dependencies, referential integrity
- * dependencies (including multi-reflexive entities), generates primary keys, creates
- * batches for massive data modifications, assigns operations to data nodes.
- *
- * @since 1.2
- * @deprecated this implementation is deprecated since 4.2, {@link DefaultDataDomainFlushAction} is used
- */
-@Deprecated
-public class LegacyDataDomainFlushAction implements org.apache.cayenne.access.flush.DataDomainFlushAction {
-
-    private final DataDomain domain;
-    private DataContext context;
-    private Map<Object, ObjectDiff> changesByObjectId;
-
-    private CompoundDiff resultDiff;
-    private Collection<ObjectId> resultDeletedIds;
-    private Map<ObjectId, DataRow> resultModifiedSnapshots;
-    private Collection<ObjectId> resultIndirectlyModifiedIds;
-
-    private DataDomainInsertBucket insertBucket;
-    private DataDomainUpdateBucket updateBucket;
-    private DataDomainDeleteBucket deleteBucket;
-    private DataDomainFlattenedBucket flattenedBucket;
-
-    private List<Query> queries;
-
-    private JdbcEventLogger logger;
-
-    public LegacyDataDomainFlushAction(DataDomain domain) {
-        this.domain = domain;
-    }
-
-    DataDomain getDomain() {
-        return domain;
-    }
-
-    DataContext getContext() {
-        return context;
-    }
-
-    Collection<ObjectId> getResultDeletedIds() {
-        return resultDeletedIds;
-    }
-
-    CompoundDiff getResultDiff() {
-        return resultDiff;
-    }
-
-    Collection<ObjectId> getResultIndirectlyModifiedIds() {
-        return resultIndirectlyModifiedIds;
-    }
-
-    Map<ObjectId, DataRow> getResultModifiedSnapshots() {
-        return resultModifiedSnapshots;
-    }
-
-    public void setJdbcEventLogger(JdbcEventLogger logger) {
-        this.logger = logger;
-    }
-
-    public JdbcEventLogger getJdbcEventLogger() {
-        return this.logger;
-    }
-
-    ObjectDiff objectDiff(Object objectId) {
-        return changesByObjectId.get(objectId);
-    }
-
-    void addFlattenedInsert(DbEntity flattenedEntity, FlattenedArcKey flattenedInsertInfo) {
-        flattenedBucket.addInsertArcKey(flattenedEntity, flattenedInsertInfo);
-    }
-
-    void addFlattenedDelete(DbEntity flattenedEntity, FlattenedArcKey flattenedDeleteInfo) {
-        flattenedBucket.addFlattenedDelete(flattenedEntity, flattenedDeleteInfo);
-    }
-
-    public GraphDiff flush(DataContext context, GraphDiff changes) {
-
-        if (changes == null) {
-            return new CompoundDiff();
-        }
-
-        // TODO: Andrus, 3/13/2006 - support categorizing an arbitrary diff
-        if (!(changes instanceof ObjectStoreGraphDiff)) {
-            throw new IllegalArgumentException("Expected 'ObjectStoreGraphDiff', got: " + changes.getClass().getName());
-        }
-
-        this.context = context;
-
-        // ObjectStoreGraphDiff contains changes already categorized by objectId...
-        this.changesByObjectId = ((ObjectStoreGraphDiff) changes).getChangesByObjectId();
-        this.insertBucket = new DataDomainInsertBucket(this);
-        this.deleteBucket = new DataDomainDeleteBucket(this);
-        this.updateBucket = new DataDomainUpdateBucket(this);
-        this.flattenedBucket = new DataDomainFlattenedBucket(this);
-
-        this.queries = new ArrayList<>();
-        this.resultIndirectlyModifiedIds = new HashSet<>();
-
-        preprocess(context, changes);
-
-        if (queries.isEmpty()) {
-            return new CompoundDiff();
-        }
-
-        this.resultDiff = new CompoundDiff();
-        this.resultDeletedIds = new ArrayList<>();
-        this.resultModifiedSnapshots = new HashMap<>();
-
-        runQueries();
-
-        postprocess(context);
-        return resultDiff;
-    }
-
-    private void preprocess(DataContext context, GraphDiff changes) {
-
-        // categorize dirty objects by state
-
-        ObjectStore objectStore = context.getObjectStore();
-
-        for (Object o : changesByObjectId.keySet()) {
-            ObjectId id = (ObjectId) o;
-            Persistent object = (Persistent) objectStore.getNode(id);
-            ClassDescriptor descriptor = context.getEntityResolver().getClassDescriptor(id.getEntityName());
-
-            switch (object.getPersistenceState()) {
-                case PersistenceState.NEW:
-                    insertBucket.addDirtyObject(object, descriptor);
-                    break;
-                case PersistenceState.MODIFIED:
-                    updateBucket.addDirtyObject(object, descriptor);
-                    break;
-                case PersistenceState.DELETED:
-                    deleteBucket.addDirtyObject(object, descriptor);
-                    break;
-            }
-        }
-
-        new DataDomainIndirectDiffBuilder(this).processIndirectChanges(changes);
-
-        insertBucket.appendQueries(queries);
-
-        // TODO: the following line depends on the "queries" collection filled by insertBucket.. Moreover it may
-        // potentially remove values from the passed collection. Replace with something with fewer unobvious
-        // side-effects...
-        flattenedBucket.appendInserts(queries);
-
-        updateBucket.appendQueries(queries);
-        flattenedBucket.appendDeletes(queries);
-        deleteBucket.appendQueries(queries);
-    }
-
-    private void runQueries() {
-        DataDomainFlushObserver observer = new DataDomainFlushObserver(
-                domain.getJdbcEventLogger());
-
-        // split query list by spanned nodes and run each single node range individually.
-        // Since connections are reused per node within an open transaction, there should
-        // not be much overhead in accessing the same node multiple times (may happen due
-        // to imperfect sorting)
-
-        try {
-
-            DataNode lastNode = null;
-            DbEntity lastEntity = null;
-            int rangeStart = 0;
-            int len = queries.size();
-
-            for (int i = 0; i < len; i++) {
-
-                BatchQuery query = (BatchQuery) queries.get(i);
-                if (query.getDbEntity() != lastEntity) {
-                    lastEntity = query.getDbEntity();
-
-                    DataNode node = domain.lookupDataNode(lastEntity.getDataMap());
-                    if (node != lastNode) {
-
-                        if (i - rangeStart > 0) {
-                            lastNode.performQueries(queries.subList(rangeStart, i), observer);
-                        }
-
-                        rangeStart = i;
-                        lastNode = node;
-                    }
-                }
-            }
-
-            // process last segment of the query list...
-            lastNode.performQueries(queries.subList(rangeStart, len), observer);
-        } catch (Throwable th) {
-            BaseTransaction.getThreadTransaction().setRollbackOnly();
-            throw new CayenneRuntimeException("Transaction was rolledback.", th);
-        }
-    }
-
-    /*
-     * Sends notification of changes to the DataRowStore, returns GraphDiff with replaced
-     * ObjectIds.
-     */
-    private void postprocess(DataContext context) {
-
-        deleteBucket.postprocess();
-        updateBucket.postprocess();
-        insertBucket.postprocess();
-
-        // notify cache...
-        if (!resultDeletedIds.isEmpty()
-                || !resultModifiedSnapshots.isEmpty()
-                || !resultIndirectlyModifiedIds.isEmpty()) {
-
-            context
-                    .getObjectStore()
-                    .getDataRowCache()
-                    .processSnapshotChanges(
-                            context.getObjectStore(),
-                            resultModifiedSnapshots,
-                            resultDeletedIds,
-                            Collections.<ObjectId>emptyList(),
-                            resultIndirectlyModifiedIds);
-        }
-
-        context.getObjectStore().postprocessAfterCommit(resultDiff);
-    }
-}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushActionFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushActionFactory.java
deleted file mode 100644
index 5ac9b2c05..000000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/LegacyDataDomainFlushActionFactory.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access;
-
-import org.apache.cayenne.access.flush.DataDomainFlushAction;
-import org.apache.cayenne.access.flush.DataDomainFlushActionFactory;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.log.JdbcEventLogger;
-
-/**
- * Factory for {@link LegacyDataDomainFlushAction}.
- * A fallback factory to use deprecated implementation if absolutely needed.
- *
- * @since 4.2
- */
-@Deprecated
-public class LegacyDataDomainFlushActionFactory implements DataDomainFlushActionFactory {
-
-    @Inject
-    private JdbcEventLogger jdbcEventLogger;
-
-    @Override
-    public DataDomainFlushAction createFlushAction(DataDomain dataDomain) {
-        LegacyDataDomainFlushAction action = new LegacyDataDomainFlushAction(dataDomain);
-        action.setJdbcEventLogger(jdbcEventLogger);
-        return action;
-    }
-}