CAY-2115 DbLoader - allow loading DataMap without Obj layer

* refactoring EntityMergeSupport


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/ac04c11b
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/ac04c11b
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/ac04c11b

Branch: refs/heads/master
Commit: ac04c11b09f6f314765e5848c864390175548745
Parents: e8e2f73
Author: Andrus Adamchik <[email protected]>
Authored: Mon Oct 3 14:04:40 2016 +0300
Committer: Andrus Adamchik <[email protected]>
Committed: Mon Oct 3 15:25:50 2016 +0300

----------------------------------------------------------------------
 .../apache/cayenne/dbsync/merge/DbMerger.java   | 704 ++++++++++---------
 .../dbsync/merge/EntityMergeSupport.java        | 117 ++-
 .../cayenne/dbsync/merge/MergerContext.java     |   5 +-
 .../cayenne/dbsync/reverse/db/DbLoader.java     |  88 +--
 .../dbsync/merge/EntityMergeSupportIT.java      |   2 +-
 .../cayenne/dbsync/reverse/db/DbLoaderIT.java   |  47 +-
 .../tools/dbimport/DbImportConfiguration.java   |  21 +-
 .../tools/dbimport/DefaultDbImportAction.java   |   1 +
 .../dbimport/DefaultDbImportActionTest.java     | 251 +++----
 .../modeler/action/CreateObjEntityAction.java   |  35 +-
 .../modeler/action/DbEntitySyncAction.java      |   2 +-
 .../cayenne/modeler/action/MigrateAction.java   |   6 +-
 .../modeler/dialog/db/DbLoaderHelper.java       |  20 +-
 .../modeler/dialog/db/ModelerDbLoader.java      |   7 +-
 .../dialog/objentity/EntitySyncController.java  |  51 +-
 15 files changed, 668 insertions(+), 689 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMerger.java
----------------------------------------------------------------------
diff --git 
a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMerger.java 
b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMerger.java
index 41ff7c8..f89dd00 100644
--- a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMerger.java
+++ b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/DbMerger.java
@@ -22,6 +22,7 @@ import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
+import org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator;
 import org.apache.cayenne.dbsync.reverse.db.DbLoader;
 import org.apache.cayenne.dbsync.reverse.db.DbLoaderConfiguration;
 import org.apache.cayenne.dbsync.reverse.db.LoggingDbLoaderDelegate;
@@ -52,354 +53,363 @@ import java.util.Set;
  * Traverse a {@link DataNode} and a {@link DataMap} and create a group of
  * {@link MergerToken}s to alter the {@link DataNode} data store to match the
  * {@link DataMap}.
- * 
  */
 public class DbMerger {
 
-       private static final Log LOGGER = LogFactory.getLog(DbMerger.class);
-
-       private final MergerTokenFactory factory;
-
-       private final ValueForNullProvider valueForNull;
-
-       public DbMerger(MergerTokenFactory factory) {
-               this(factory, null);
-       }
-
-       public DbMerger(MergerTokenFactory factory, ValueForNullProvider 
valueForNull) {
-               this.factory = factory;
-               this.valueForNull = valueForNull == null ? new 
EmptyValueForNullProvider() : valueForNull;
-       }
-
-       /**
-        * Create and return a {@link List} of {@link MergerToken}s to alter the
-        * given {@link DataNode} to match the given {@link DataMap}
-        */
-       public List<MergerToken> createMergeTokens(DataSource dataSource, 
DbAdapter adapter, DataMap existingDataMap,
-                       DbLoaderConfiguration config) {
-               return createMergeTokens(existingDataMap, 
loadDataMapFromDb(dataSource, adapter, config), config);
-       }
-
-       /**
-        * Create and return a {@link List} of {@link MergerToken}s to alter the
-        * given {@link DataNode} to match the given {@link DataMap}
-        */
-       public List<MergerToken> createMergeTokens(DataMap existing, DataMap 
loadedFomDb, DbLoaderConfiguration config) {
-
-               
loadedFomDb.setQuotingSQLIdentifiers(existing.isQuotingSQLIdentifiers());
-
-               List<MergerToken> tokens = createMergeTokens(filter(existing, 
config.getFiltersConfig()),
-                               loadedFomDb.getDbEntities(), config);
-
-               // sort. use a custom Comparator since only toDb tokens are 
comparable
-               // by now
-               Collections.sort(tokens, new Comparator<MergerToken>() {
-
-                       public int compare(MergerToken o1, MergerToken o2) {
-                               if (o1 instanceof AbstractToDbToken && o2 
instanceof AbstractToDbToken) {
-
-                                       return ((AbstractToDbToken) 
o1).compareTo(o2);
-                               }
-                               return 0;
-                       }
-               });
-
-               return tokens;
-       }
-
-       private Collection<DbEntity> filter(DataMap existing, FiltersConfig 
filtersConfig) {
-               Collection<DbEntity> existingFiltered = new 
LinkedList<DbEntity>();
-               for (DbEntity entity : existing.getDbEntities()) {
-                       if (filtersConfig.tableFilter(entity.getCatalog(), 
entity.getSchema()).isIncludeTable(entity.getName()) != null) {
-                               existingFiltered.add(entity);
-                       }
-               }
-               return existingFiltered;
-       }
-
-       private DataMap loadDataMapFromDb(DataSource dataSource, DbAdapter 
adapter, DbLoaderConfiguration config) {
-               try (Connection conn = dataSource.getConnection();) {
-
-                       return new DbLoader(conn, adapter, new 
LoggingDbLoaderDelegate(LOGGER)).load(config);
-               } catch (SQLException e) {
-                       throw new CayenneRuntimeException("Can't doLoad dataMap 
from db.", e);
-               }
-       }
-
-       public List<MergerToken> createMergeTokens(Collection<DbEntity> 
existing, Collection<DbEntity> loadedFromDb,
-                       DbLoaderConfiguration config) {
-               Collection<DbEntity> dbEntitiesToDrop = new 
LinkedList<DbEntity>(loadedFromDb);
-
-               List<MergerToken> tokens = new LinkedList<MergerToken>();
-               for (DbEntity dbEntity : existing) {
-                       String tableName = dbEntity.getName();
-
-                       // look for table
-                       DbEntity detectedEntity = findDbEntity(loadedFromDb, 
tableName);
-                       if (detectedEntity == null) {
-                               
tokens.add(factory.createCreateTableToDb(dbEntity));
-                               // TODO: does this work properly with 
createReverse?
-                               for (DbRelationship rel : 
dbEntity.getRelationships()) {
-                                       
tokens.add(factory.createAddRelationshipToDb(dbEntity, rel));
-                               }
-                               continue;
-                       }
-
-                       dbEntitiesToDrop.remove(detectedEntity);
-
-                       tokens.addAll(checkRelationshipsToDrop(dbEntity, 
detectedEntity));
-                       if (!config.isSkipRelationshipsLoading()) {
-                               tokens.addAll(checkRelationshipsToAdd(dbEntity, 
detectedEntity));
-                       }
-                       tokens.addAll(checkRows(dbEntity, detectedEntity));
-
-                       if (!config.isSkipPrimaryKeyLoading()) {
-                               MergerToken token = 
checkPrimaryKeyChange(dbEntity, detectedEntity);
-                               if (token != null) {
-                                       tokens.add(token);
-                               }
-                       }
-               }
-
-               // drop table
-               // TODO: support drop table. currently, too many tables are 
marked for
-               // drop
-               for (DbEntity e : dbEntitiesToDrop) {
-                       tokens.add(factory.createDropTableToDb(e));
-                       for (DbRelationship relationship : 
e.getRelationships()) {
-                               DbEntity detectedEntity = 
findDbEntity(existing, relationship.getTargetEntityName());
-                               if (detectedEntity != null) {
-                                       
tokens.add(factory.createDropRelationshipToDb(detectedEntity, 
relationship.getReverseRelationship()));
-                               }
-                       }
-               }
-
-               return tokens;
-       }
-
-       private List<MergerToken> checkRows(DbEntity existing, DbEntity 
loadedFromDb) {
-               List<MergerToken> tokens = new LinkedList<MergerToken>();
-
-               // columns to drop
-               for (DbAttribute detected : loadedFromDb.getAttributes()) {
-                       if (findDbAttribute(existing, detected.getName()) == 
null) {
-                               
tokens.add(factory.createDropColumnToDb(existing, detected));
-                       }
-               }
-
-               // columns to add or modify
-               for (DbAttribute attr : existing.getAttributes()) {
-                       String columnName = attr.getName().toUpperCase();
-
-                       DbAttribute detected = findDbAttribute(loadedFromDb, 
columnName);
-
-                       if (detected == null) {
-                               
tokens.add(factory.createAddColumnToDb(existing, attr));
-                               if (attr.isMandatory()) {
-                                       if (valueForNull.hasValueFor(existing, 
attr)) {
-                                               
tokens.add(factory.createSetValueForNullToDb(existing, attr, valueForNull));
-                                       }
-                                       
tokens.add(factory.createSetNotNullToDb(existing, attr));
-                               }
-                               continue;
-                       }
-
-                       // check for not null
-                       if (attr.isMandatory() != detected.isMandatory()) {
-                               if (attr.isMandatory()) {
-                                       if (valueForNull.hasValueFor(existing, 
attr)) {
-                                               
tokens.add(factory.createSetValueForNullToDb(existing, attr, valueForNull));
-                                       }
-                                       
tokens.add(factory.createSetNotNullToDb(existing, attr));
-                               } else {
-                                       
tokens.add(factory.createSetAllowNullToDb(existing, attr));
-                               }
-                       }
-
-                       // TODO: check more types than char/varchar
-                       // TODO: psql report VARCHAR for text column, not clob
-                       switch (detected.getType()) {
-                       case Types.VARCHAR:
-                       case Types.CHAR:
-                               if (attr.getMaxLength() != 
detected.getMaxLength()) {
-                                       
tokens.add(factory.createSetColumnTypeToDb(existing, detected, attr));
-                               }
-                               break;
-                       }
-               }
-
-               return tokens;
-       }
-
-       private List<MergerToken> checkRelationshipsToDrop(DbEntity dbEntity, 
DbEntity detectedEntity) {
-               List<MergerToken> tokens = new LinkedList<MergerToken>();
-
-               // relationships to drop
-               for (DbRelationship detected : 
detectedEntity.getRelationships()) {
-                       if (findDbRelationship(dbEntity, detected) == null) {
-
-                               // alter detected relationship to match entity 
and attribute
-                               // names.
-                               // (case sensitively)
-
-                               DbEntity targetEntity = 
findDbEntity(dbEntity.getDataMap().getDbEntities(),
-                                               detected.getTargetEntityName());
-                               if (targetEntity == null) {
-                                       continue;
-                               }
-
-                               detected.setSourceEntity(dbEntity);
-                               detected.setTargetEntityName(targetEntity);
-
-                               // manipulate the joins to match the 
DbAttributes in the model
-                               for (DbJoin join : detected.getJoins()) {
-                                       DbAttribute sattr = 
findDbAttribute(dbEntity, join.getSourceName());
-                                       if (sattr != null) {
-                                               
join.setSourceName(sattr.getName());
-                                       }
-                                       DbAttribute tattr = 
findDbAttribute(targetEntity, join.getTargetName());
-                                       if (tattr != null) {
-                                               
join.setTargetName(tattr.getName());
-                                       }
-                               }
-
-                               MergerToken token = 
factory.createDropRelationshipToDb(dbEntity, detected);
-                               if (detected.isToMany()) {
-                                       // default toModel as we can not do 
drop a toMany in the db.
-                                       // only
-                                       // toOne are represented using foreign 
key
-                                       token = token.createReverse(factory);
-                               }
-                               tokens.add(token);
-                       }
-               }
-
-               return tokens;
-       }
-
-       private List<MergerToken> checkRelationshipsToAdd(DbEntity dbEntity, 
DbEntity detectedEntity) {
-
-               List<MergerToken> tokens = new LinkedList<MergerToken>();
-
-               for (DbRelationship rel : dbEntity.getRelationships()) {
-                       if (findDbRelationship(detectedEntity, rel) == null) {
-                               AddRelationshipToDb token = 
(AddRelationshipToDb) factory.createAddRelationshipToDb(dbEntity, rel);
-
-                               if (token.shouldGenerateFkConstraint()) {
-                                       // TODO I guess we should add 
relationship always; in order
-                                       // to have ability
-                                       // TODO generate reverse relationship. 
If it doesn't have
-                                       // anything to execute it will be passed
-                                       // TODO through execution without any 
affect on db
-                                       tokens.add(token);
-                               }
-                       }
-               }
-
-               return tokens;
-       }
-
-       private MergerToken checkPrimaryKeyChange(DbEntity dbEntity, DbEntity 
detectedEntity) {
-               Collection<DbAttribute> primaryKeyOriginal = 
detectedEntity.getPrimaryKeys();
-               Collection<DbAttribute> primaryKeyNew = 
dbEntity.getPrimaryKeys();
-
-               String primaryKeyName = null;
-               if (detectedEntity instanceof DetectedDbEntity) {
-                       primaryKeyName = ((DetectedDbEntity) 
detectedEntity).getPrimaryKeyName();
-               }
-
-               if 
(upperCaseEntityNames(primaryKeyOriginal).equals(upperCaseEntityNames(primaryKeyNew)))
 {
-                       return null;
-               }
-
-               return factory.createSetPrimaryKeyToDb(dbEntity, 
primaryKeyOriginal, primaryKeyNew, primaryKeyName);
-       }
-
-       private Set<String> upperCaseEntityNames(Collection<? extends 
Attribute> attrs) {
-               Set<String> names = new HashSet<String>();
-               for (Attribute attr : attrs) {
-                       names.add(attr.getName().toUpperCase());
-               }
-               return names;
-       }
-
-       /**
-        * case insensitive search for a {@link DbEntity} in a {@link DataMap} 
by
-        * name
-        */
-       private DbEntity findDbEntity(Collection<DbEntity> dbEntities, String 
caseInsensitiveName) {
-               // TODO: create a Map with upper case keys?
-               for (DbEntity e : dbEntities) {
-                       if (e.getName().equalsIgnoreCase(caseInsensitiveName)) {
-                               return e;
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * case insensitive search for a {@link DbAttribute} in a {@link 
DbEntity}
-        * by name
-        */
-       private DbAttribute findDbAttribute(DbEntity entity, String 
caseInsensitiveName) {
-               for (DbAttribute a : entity.getAttributes()) {
-                       if (a.getName().equalsIgnoreCase(caseInsensitiveName)) {
-                               return a;
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * search for a {@link DbRelationship} like rel in the given
-        * {@link DbEntity}
-        */
-       private DbRelationship findDbRelationship(DbEntity entity, 
DbRelationship rel) {
-               for (DbRelationship candidate : entity.getRelationships()) {
-                       if (equalDbJoinCollections(candidate.getJoins(), 
rel.getJoins())) {
-                               return candidate;
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * Return true if the two unordered {@link Collection}s of {@link 
DbJoin}s
-        * are equal. Entity and Attribute names are compared case 
insensitively.
-        *
-        * TODO complexity n^2; sort both collection and go through them to 
compare
-        * = 2*n*log(n) + n
-        */
-       private static boolean equalDbJoinCollections(Collection<DbJoin> j1s, 
Collection<DbJoin> j2s) {
-               if (j1s.size() != j2s.size()) {
-                       return false;
-               }
-
-               for (DbJoin j1 : j1s) {
-                       if (!havePair(j2s, j1)) {
-                               return false;
-                       }
-               }
-
-               return true;
-       }
-
-       private static boolean havePair(Collection<DbJoin> j2s, DbJoin j1) {
-               for (DbJoin j2 : j2s) {
-                       if (!isNull(j1.getSource()) && !isNull(j1.getTarget()) 
&& !isNull(j2.getSource())
-                                       && !isNull(j2.getTarget())
-                                       && 
j1.getSource().getEntity().getName().equalsIgnoreCase(j2.getSource().getEntity().getName())
-                                       && 
j1.getTarget().getEntity().getName().equalsIgnoreCase(j2.getTarget().getEntity().getName())
-                                       && 
j1.getSourceName().equalsIgnoreCase(j2.getSourceName())
-                                       && 
j1.getTargetName().equalsIgnoreCase(j2.getTargetName())) {
-
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-       private static boolean isNull(DbAttribute attribute) {
-               return attribute == null || attribute.getEntity() == null;
-       }
+    private static final Log LOGGER = LogFactory.getLog(DbMerger.class);
+
+    private final MergerTokenFactory factory;
+
+    private final ValueForNullProvider valueForNull;
+
+    public DbMerger(MergerTokenFactory factory) {
+        this(factory, null);
+    }
+
+    public DbMerger(MergerTokenFactory factory, ValueForNullProvider 
valueForNull) {
+        this.factory = factory;
+        this.valueForNull = valueForNull == null ? new 
EmptyValueForNullProvider() : valueForNull;
+    }
+
+    /**
+     * Return true if the two unordered {@link Collection}s of {@link DbJoin}s
+     * are equal. Entity and Attribute names are compared case insensitively.
+     * <p>
+     * TODO complexity n^2; sort both collection and go through them to compare
+     * = 2*n*log(n) + n
+     */
+    private static boolean equalDbJoinCollections(Collection<DbJoin> j1s, 
Collection<DbJoin> j2s) {
+        if (j1s.size() != j2s.size()) {
+            return false;
+        }
+
+        for (DbJoin j1 : j1s) {
+            if (!havePair(j2s, j1)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean havePair(Collection<DbJoin> j2s, DbJoin j1) {
+        for (DbJoin j2 : j2s) {
+            if (!isNull(j1.getSource()) && !isNull(j1.getTarget()) && 
!isNull(j2.getSource())
+                    && !isNull(j2.getTarget())
+                    && 
j1.getSource().getEntity().getName().equalsIgnoreCase(j2.getSource().getEntity().getName())
+                    && 
j1.getTarget().getEntity().getName().equalsIgnoreCase(j2.getTarget().getEntity().getName())
+                    && j1.getSourceName().equalsIgnoreCase(j2.getSourceName())
+                    && 
j1.getTargetName().equalsIgnoreCase(j2.getTargetName())) {
+
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isNull(DbAttribute attribute) {
+        return attribute == null || attribute.getEntity() == null;
+    }
+
+    /**
+     * Create and return a {@link List} of {@link MergerToken}s to alter the
+     * given {@link DataNode} to match the given {@link DataMap}
+     */
+    public List<MergerToken> createMergeTokens(DataSource dataSource, 
DbAdapter adapter, DataMap existingDataMap,
+                                               DbLoaderConfiguration config) {
+        return createMergeTokens(existingDataMap, 
loadDataMapFromDb(dataSource, adapter, config), config);
+    }
+
+    /**
+     * Create and return a {@link List} of {@link MergerToken}s to alter the
+     * given {@link DataNode} to match the given {@link DataMap}
+     */
+    public List<MergerToken> createMergeTokens(DataMap existing, DataMap 
loadedFomDb, DbLoaderConfiguration config) {
+
+        
loadedFomDb.setQuotingSQLIdentifiers(existing.isQuotingSQLIdentifiers());
+
+        List<MergerToken> tokens = createMergeTokens(filter(existing, 
config.getFiltersConfig()),
+                loadedFomDb.getDbEntities(), config);
+
+        // sort. use a custom Comparator since only toDb tokens are comparable
+        // by now
+        Collections.sort(tokens, new Comparator<MergerToken>() {
+
+            public int compare(MergerToken o1, MergerToken o2) {
+                if (o1 instanceof AbstractToDbToken && o2 instanceof 
AbstractToDbToken) {
+
+                    return ((AbstractToDbToken) o1).compareTo(o2);
+                }
+                return 0;
+            }
+        });
+
+        return tokens;
+    }
+
+    private Collection<DbEntity> filter(DataMap existing, FiltersConfig 
filtersConfig) {
+        Collection<DbEntity> existingFiltered = new LinkedList<DbEntity>();
+        for (DbEntity entity : existing.getDbEntities()) {
+            if (filtersConfig.tableFilter(entity.getCatalog(), 
entity.getSchema()).isIncludeTable(entity.getName()) != null) {
+                existingFiltered.add(entity);
+            }
+        }
+        return existingFiltered;
+    }
+
+    protected EntityMergeSupport createEntityMergeSupport() {
+        return new EntityMergeSupport(new DefaultObjectNameGenerator(), true, 
true);
+    }
+
+    private DataMap loadDataMapFromDb(DataSource dataSource, DbAdapter 
adapter, DbLoaderConfiguration config) {
+
+
+        try (Connection conn = dataSource.getConnection();) {
+
+            return new DbLoader(conn,
+                    adapter,
+                    new LoggingDbLoaderDelegate(LOGGER),
+                    createEntityMergeSupport()).load(config);
+
+        } catch (SQLException e) {
+            throw new CayenneRuntimeException("Can't doLoad dataMap from db.", 
e);
+        }
+    }
+
+    public List<MergerToken> createMergeTokens(Collection<DbEntity> existing, 
Collection<DbEntity> loadedFromDb,
+                                               DbLoaderConfiguration config) {
+        Collection<DbEntity> dbEntitiesToDrop = new 
LinkedList<DbEntity>(loadedFromDb);
+
+        List<MergerToken> tokens = new LinkedList<MergerToken>();
+        for (DbEntity dbEntity : existing) {
+            String tableName = dbEntity.getName();
+
+            // look for table
+            DbEntity detectedEntity = findDbEntity(loadedFromDb, tableName);
+            if (detectedEntity == null) {
+                tokens.add(factory.createCreateTableToDb(dbEntity));
+                // TODO: does this work properly with createReverse?
+                for (DbRelationship rel : dbEntity.getRelationships()) {
+                    tokens.add(factory.createAddRelationshipToDb(dbEntity, 
rel));
+                }
+                continue;
+            }
+
+            dbEntitiesToDrop.remove(detectedEntity);
+
+            tokens.addAll(checkRelationshipsToDrop(dbEntity, detectedEntity));
+            if (!config.isSkipRelationshipsLoading()) {
+                tokens.addAll(checkRelationshipsToAdd(dbEntity, 
detectedEntity));
+            }
+            tokens.addAll(checkRows(dbEntity, detectedEntity));
+
+            if (!config.isSkipPrimaryKeyLoading()) {
+                MergerToken token = checkPrimaryKeyChange(dbEntity, 
detectedEntity);
+                if (token != null) {
+                    tokens.add(token);
+                }
+            }
+        }
+
+        // drop table
+        // TODO: support drop table. currently, too many tables are marked for
+        // drop
+        for (DbEntity e : dbEntitiesToDrop) {
+            tokens.add(factory.createDropTableToDb(e));
+            for (DbRelationship relationship : e.getRelationships()) {
+                DbEntity detectedEntity = findDbEntity(existing, 
relationship.getTargetEntityName());
+                if (detectedEntity != null) {
+                    
tokens.add(factory.createDropRelationshipToDb(detectedEntity, 
relationship.getReverseRelationship()));
+                }
+            }
+        }
+
+        return tokens;
+    }
+
+    private List<MergerToken> checkRows(DbEntity existing, DbEntity 
loadedFromDb) {
+        List<MergerToken> tokens = new LinkedList<MergerToken>();
+
+        // columns to drop
+        for (DbAttribute detected : loadedFromDb.getAttributes()) {
+            if (findDbAttribute(existing, detected.getName()) == null) {
+                tokens.add(factory.createDropColumnToDb(existing, detected));
+            }
+        }
+
+        // columns to add or modify
+        for (DbAttribute attr : existing.getAttributes()) {
+            String columnName = attr.getName().toUpperCase();
+
+            DbAttribute detected = findDbAttribute(loadedFromDb, columnName);
+
+            if (detected == null) {
+                tokens.add(factory.createAddColumnToDb(existing, attr));
+                if (attr.isMandatory()) {
+                    if (valueForNull.hasValueFor(existing, attr)) {
+                        tokens.add(factory.createSetValueForNullToDb(existing, 
attr, valueForNull));
+                    }
+                    tokens.add(factory.createSetNotNullToDb(existing, attr));
+                }
+                continue;
+            }
+
+            // check for not null
+            if (attr.isMandatory() != detected.isMandatory()) {
+                if (attr.isMandatory()) {
+                    if (valueForNull.hasValueFor(existing, attr)) {
+                        tokens.add(factory.createSetValueForNullToDb(existing, 
attr, valueForNull));
+                    }
+                    tokens.add(factory.createSetNotNullToDb(existing, attr));
+                } else {
+                    tokens.add(factory.createSetAllowNullToDb(existing, attr));
+                }
+            }
+
+            // TODO: check more types than char/varchar
+            // TODO: psql report VARCHAR for text column, not clob
+            switch (detected.getType()) {
+                case Types.VARCHAR:
+                case Types.CHAR:
+                    if (attr.getMaxLength() != detected.getMaxLength()) {
+                        tokens.add(factory.createSetColumnTypeToDb(existing, 
detected, attr));
+                    }
+                    break;
+            }
+        }
+
+        return tokens;
+    }
+
+    private List<MergerToken> checkRelationshipsToDrop(DbEntity dbEntity, 
DbEntity detectedEntity) {
+        List<MergerToken> tokens = new LinkedList<MergerToken>();
+
+        // relationships to drop
+        for (DbRelationship detected : detectedEntity.getRelationships()) {
+            if (findDbRelationship(dbEntity, detected) == null) {
+
+                // alter detected relationship to match entity and attribute
+                // names.
+                // (case sensitively)
+
+                DbEntity targetEntity = 
findDbEntity(dbEntity.getDataMap().getDbEntities(),
+                        detected.getTargetEntityName());
+                if (targetEntity == null) {
+                    continue;
+                }
+
+                detected.setSourceEntity(dbEntity);
+                detected.setTargetEntityName(targetEntity);
+
+                // manipulate the joins to match the DbAttributes in the model
+                for (DbJoin join : detected.getJoins()) {
+                    DbAttribute sattr = findDbAttribute(dbEntity, 
join.getSourceName());
+                    if (sattr != null) {
+                        join.setSourceName(sattr.getName());
+                    }
+                    DbAttribute tattr = findDbAttribute(targetEntity, 
join.getTargetName());
+                    if (tattr != null) {
+                        join.setTargetName(tattr.getName());
+                    }
+                }
+
+                MergerToken token = 
factory.createDropRelationshipToDb(dbEntity, detected);
+                if (detected.isToMany()) {
+                    // default toModel as we can not do drop a toMany in the 
db.
+                    // only
+                    // toOne are represented using foreign key
+                    token = token.createReverse(factory);
+                }
+                tokens.add(token);
+            }
+        }
+
+        return tokens;
+    }
+
+    private List<MergerToken> checkRelationshipsToAdd(DbEntity dbEntity, 
DbEntity detectedEntity) {
+
+        List<MergerToken> tokens = new LinkedList<MergerToken>();
+
+        for (DbRelationship rel : dbEntity.getRelationships()) {
+            if (findDbRelationship(detectedEntity, rel) == null) {
+                AddRelationshipToDb token = (AddRelationshipToDb) 
factory.createAddRelationshipToDb(dbEntity, rel);
+
+                if (token.shouldGenerateFkConstraint()) {
+                    // TODO I guess we should add relationship always; in order
+                    // to have ability
+                    // TODO generate reverse relationship. If it doesn't have
+                    // anything to execute it will be passed
+                    // TODO through execution without any affect on db
+                    tokens.add(token);
+                }
+            }
+        }
+
+        return tokens;
+    }
+
+    private MergerToken checkPrimaryKeyChange(DbEntity dbEntity, DbEntity 
detectedEntity) {
+        Collection<DbAttribute> primaryKeyOriginal = 
detectedEntity.getPrimaryKeys();
+        Collection<DbAttribute> primaryKeyNew = dbEntity.getPrimaryKeys();
+
+        String primaryKeyName = null;
+        if (detectedEntity instanceof DetectedDbEntity) {
+            primaryKeyName = ((DetectedDbEntity) 
detectedEntity).getPrimaryKeyName();
+        }
+
+        if 
(upperCaseEntityNames(primaryKeyOriginal).equals(upperCaseEntityNames(primaryKeyNew)))
 {
+            return null;
+        }
+
+        return factory.createSetPrimaryKeyToDb(dbEntity, primaryKeyOriginal, 
primaryKeyNew, primaryKeyName);
+    }
+
+    private Set<String> upperCaseEntityNames(Collection<? extends Attribute> 
attrs) {
+        Set<String> names = new HashSet<String>();
+        for (Attribute attr : attrs) {
+            names.add(attr.getName().toUpperCase());
+        }
+        return names;
+    }
+
+    /**
+     * case insensitive search for a {@link DbEntity} in a {@link DataMap} by
+     * name
+     */
+    private DbEntity findDbEntity(Collection<DbEntity> dbEntities, String 
caseInsensitiveName) {
+        // TODO: create a Map with upper case keys?
+        for (DbEntity e : dbEntities) {
+            if (e.getName().equalsIgnoreCase(caseInsensitiveName)) {
+                return e;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * case insensitive search for a {@link DbAttribute} in a {@link DbEntity}
+     * by name
+     */
+    private DbAttribute findDbAttribute(DbEntity entity, String 
caseInsensitiveName) {
+        for (DbAttribute a : entity.getAttributes()) {
+            if (a.getName().equalsIgnoreCase(caseInsensitiveName)) {
+                return a;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * search for a {@link DbRelationship} like rel in the given
+     * {@link DbEntity}
+     */
+    private DbRelationship findDbRelationship(DbEntity entity, DbRelationship 
rel) {
+        for (DbRelationship candidate : entity.getRelationships()) {
+            if (equalDbJoinCollections(candidate.getJoins(), rel.getJoins())) {
+                return candidate;
+            }
+        }
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java
----------------------------------------------------------------------
diff --git 
a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java
 
b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java
index 11f2ac4..bf54dcc 100644
--- 
a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java
+++ 
b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/EntityMergeSupport.java
@@ -48,7 +48,7 @@ import java.util.Map;
  */
 public class EntityMergeSupport {
 
-    private static final Log LOG = LogFactory.getLog(EntityMergeSupport.class);
+    private static final Log LOGGER = 
LogFactory.getLog(EntityMergeSupport.class);
 
     private static final Map<String, String> CLASS_TO_PRIMITIVE;
 
@@ -63,41 +63,36 @@ public class EntityMergeSupport {
         CLASS_TO_PRIMITIVE.put(Integer.class.getName(), "int");
     }
 
-    private final DataMap map;
-    /**
-     * Strategy for choosing names for entities, attributes and relationships
-     */
     private final ObjectNameGenerator nameGenerator;
-    /**
-     * Listeners of merge process.
-     */
-    private final List<EntityMergeListener> listeners = new 
ArrayList<EntityMergeListener>();
-    protected boolean removeMeaningfulFKs;
-    protected boolean removeMeaningfulPKs;
-    protected boolean usePrimitives;
-    
-    /**
-     * @since 3.0
-     */
-    public EntityMergeSupport(DataMap map, ObjectNameGenerator nameGenerator, 
boolean removeMeaningfulPKs) {
-        this.map = map;
+    private final List<EntityMergeListener> listeners;
+    protected boolean removingMeaningfulFKs;
+    protected boolean removingMeaningfulPKs;
+    protected boolean usingPrimitives;
+
+    public EntityMergeSupport(ObjectNameGenerator nameGenerator, boolean 
removingMeaningfulPKs, boolean removingMeaningfulFKs) {
+        this.listeners = new ArrayList<>();
         this.nameGenerator = nameGenerator;
-        this.removeMeaningfulFKs = true;
-        this.removeMeaningfulPKs = removeMeaningfulPKs;
+        this.removingMeaningfulFKs = removingMeaningfulFKs;
+        this.removingMeaningfulPKs = removingMeaningfulPKs;
 
-        /**
-         * Adding a listener, so that all created ObjRelationships would have
-         * default delete rule
-         */
+        // will ensure that all created ObjRelationships would have
+        // default delete rule
         addEntityMergeListener(DeleteRuleUpdater.getEntityMergeListener());
     }
 
+    public boolean isRemovingMeaningfulFKs() {
+        return removingMeaningfulFKs;
+    }
+
+    public boolean isRemovingMeaningfulPKs() {
+        return removingMeaningfulPKs;
+    }
+
     /**
      * Updates each one of the collection of ObjEntities, adding attributes and
      * relationships based on the current state of its DbEntity.
      *
      * @return true if any ObjEntity has changed as a result of 
synchronization.
-     * @since 1.2 changed signature to use Collection instead of List.
      */
     public boolean synchronizeWithDbEntities(Iterable<ObjEntity> objEntities) {
         boolean changed = false;
@@ -114,14 +109,14 @@ public class EntityMergeSupport {
      * @since 4.0
      */
     protected boolean removePK(DbEntity dbEntity) {
-        return removeMeaningfulPKs;
+        return removingMeaningfulPKs;
     }
 
     /**
      * @since 4.0
      */
     protected boolean removeFK(DbEntity dbEntity) {
-        return removeMeaningfulFKs;
+        return removingMeaningfulFKs;
     }
 
     /**
@@ -143,18 +138,13 @@ public class EntityMergeSupport {
 
         boolean changed = false;
 
-        // synchronization on DataMap is some (weak) protection
-        // against simultaneous modification of the map (like double-clicking 
on sync button)
-        synchronized (map) {
-
-            if (removeFK(dbEntity)) {
-                changed = 
getRidOfAttributesThatAreNowSrcAttributesForRelationships(entity);
-            }
-
-            changed |= addMissingAttributes(entity);
-            changed |= addMissingRelationships(entity);
+        if (removeFK(dbEntity)) {
+            changed = 
getRidOfAttributesThatAreNowSrcAttributesForRelationships(entity);
         }
 
+        changed |= addMissingAttributes(entity);
+        changed |= addMissingRelationships(entity);
+
         return changed;
     }
 
@@ -249,15 +239,14 @@ public class EntityMergeSupport {
     }
 
     private void addMissingRelationship(ObjEntity entity, DbRelationship 
dbRelationship) {
-        DbEntity targetEntity = dbRelationship.getTargetEntity();
 
-        Collection<ObjEntity> mappedObjEntities = 
map.getMappedEntities(targetEntity);
-        if (!mappedObjEntities.isEmpty()) {
-            for (Entity mappedTarget : mappedObjEntities) {
-                createObjRelationship(entity, dbRelationship, 
mappedTarget.getName());
-            }
-        } else {
+        // getting DataMap from DbRelationship's source entity. This is the 
only object in our arguments that
+        // is guaranteed to be a part of the map....
+        DataMap dataMap = dbRelationship.getSourceEntity().getDataMap();
 
+        DbEntity targetEntity = dbRelationship.getTargetEntity();
+        Collection<ObjEntity> mappedObjEntities = 
dataMap.getMappedEntities(targetEntity);
+        if (mappedObjEntities.isEmpty()) {
             if (targetEntity == null) {
                 targetEntity = new 
DbEntity(dbRelationship.getTargetEntityName());
             }
@@ -266,10 +255,14 @@ public class EntityMergeSupport {
                 boolean needGeneratedEntity = createObjRelationship(entity, 
dbRelationship,
                         nameGenerator.objEntityName(targetEntity));
                 if (needGeneratedEntity) {
-                    LOG.warn("Can't find ObjEntity for " + 
dbRelationship.getTargetEntityName());
-                    LOG.warn("Db Relationship (" + dbRelationship + ") will 
have GUESSED Obj Relationship reflection. ");
+                    LOGGER.warn("Can't find ObjEntity for " + 
dbRelationship.getTargetEntityName());
+                    LOGGER.warn("Db Relationship (" + dbRelationship + ") will 
have GUESSED Obj Relationship reflection. ");
                 }
             }
+        } else {
+            for (Entity mappedTarget : mappedObjEntities) {
+                createObjRelationship(entity, dbRelationship, 
mappedTarget.getName());
+            }
         }
     }
 
@@ -281,7 +274,7 @@ public class EntityMergeSupport {
         oa.setEntity(entity);
 
         String type = TypesMapping.getJavaBySqlType(da.getType());
-        if (usePrimitives) {
+        if (usingPrimitives) {
             String primitive = CLASS_TO_PRIMITIVE.get(type);
             if (primitive != null) {
                 type = primitive;
@@ -313,7 +306,7 @@ public class EntityMergeSupport {
      * @since 1.2
      */
     public Collection<DbAttribute> getMeaningfulFKs(ObjEntity objEntity) {
-        List<DbAttribute> fks = new ArrayList<DbAttribute>(2);
+        List<DbAttribute> fks = new ArrayList<>(2);
 
         for (ObjAttribute property : objEntity.getAttributes()) {
             DbAttribute column = property.getDbAttribute();
@@ -334,7 +327,7 @@ public class EntityMergeSupport {
     protected List<DbAttribute> getAttributesToAdd(ObjEntity objEntity) {
         DbEntity dbEntity = objEntity.getDbEntity();
 
-        List<DbAttribute> missing = new ArrayList<DbAttribute>();
+        List<DbAttribute> missing = new ArrayList<>();
         Collection<DbRelationship> incomingRels = 
getIncomingRelationships(dbEntity);
 
         for (DbAttribute dba : dbEntity.getAttributes()) {
@@ -443,20 +436,6 @@ public class EntityMergeSupport {
     }
 
     /**
-     * @since 1.2
-     */
-    public boolean isRemoveMeaningfulFKs() {
-        return removeMeaningfulFKs;
-    }
-
-    /**
-     * @since 1.2
-     */
-    public void setRemoveMeaningfulFKs(boolean removeMeaningfulFKs) {
-        this.removeMeaningfulFKs = removeMeaningfulFKs;
-    }
-
-    /**
      * Registers new EntityMergeListener
      */
     public void addEntityMergeListener(EntityMergeListener listener) {
@@ -496,7 +475,7 @@ public class EntityMergeSupport {
     }
 
     /**
-     * @return naming strategy for reverse engineering
+     * @return a strategy for naming object layer artifacts based on their DB 
names.
      */
     public ObjectNameGenerator getNameGenerator() {
         return nameGenerator;
@@ -505,15 +484,15 @@ public class EntityMergeSupport {
     /**
      * @since 4.0
      */
-    public boolean isUsePrimitives() {
-        return usePrimitives;
+    public boolean isUsingPrimitives() {
+        return usingPrimitives;
     }
 
     /**
-     * @param usePrimitives
+     * @param usingPrimitives
      * @since 4.0
      */
-    public void setUsePrimitives(boolean usePrimitives) {
-        this.usePrimitives = usePrimitives;
+    public void setUsingPrimitives(boolean usingPrimitives) {
+        this.usingPrimitives = usingPrimitives;
     }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerContext.java
----------------------------------------------------------------------
diff --git 
a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerContext.java
 
b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerContext.java
index 77f9e61..57eab3e 100644
--- 
a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerContext.java
+++ 
b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/merge/MergerContext.java
@@ -135,9 +135,8 @@ public class MergerContext {
         }
 
         public Builder nameGenerator(ObjectNameGenerator nameGenerator) {
-            context.entityMergeSupport = new 
EntityMergeSupport(context.getDataMap(),
-                    Objects.requireNonNull(nameGenerator),
-                    true);  // should the last argument also be a part of the 
builder?
+            // should the last argument also be a part of the builder?
+            context.entityMergeSupport = new 
EntityMergeSupport(Objects.requireNonNull(nameGenerator), true, true);
             return this;
         }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java
----------------------------------------------------------------------
diff --git 
a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java
 
b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java
index 888d6d4..7220b97 100644
--- 
a/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java
+++ 
b/cayenne-dbsync/src/main/java/org/apache/cayenne/dbsync/reverse/db/DbLoader.java
@@ -22,12 +22,11 @@ import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.dbsync.merge.EntityMergeSupport;
 import org.apache.cayenne.dbsync.naming.NameBuilder;
+import org.apache.cayenne.dbsync.naming.ObjectNameGenerator;
 import org.apache.cayenne.dbsync.reverse.filters.CatalogFilter;
 import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
 import org.apache.cayenne.dbsync.reverse.filters.SchemaFilter;
 import org.apache.cayenne.dbsync.reverse.filters.TableFilter;
-import org.apache.cayenne.dbsync.naming.LegacyObjectNameGenerator;
-import org.apache.cayenne.dbsync.naming.ObjectNameGenerator;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
@@ -51,6 +50,7 @@ import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.TreeSet;
 
@@ -70,38 +70,18 @@ public class DbLoader {
     private final DbAdapter adapter;
     private final DbLoaderDelegate delegate;
 
-    private boolean creatingMeaningfulPK;
-
-    /**
-     * Strategy for choosing names for entities, attributes and relationships
-     */
-    private ObjectNameGenerator nameGenerator;
-
+    private EntityMergeSupport entityMergeSupport;
     private DatabaseMetaData metaData;
 
-
-    /**
-     * Creates new DbLoader.
-     */
-    public DbLoader(Connection connection, DbAdapter adapter, DbLoaderDelegate 
delegate) {
-        this(connection, adapter, delegate, new LegacyObjectNameGenerator());
-    }
-
-    /**
-     * Creates new DbLoader with specified naming strategy.
-     *
-     * @since 3.0
-     */
-    public DbLoader(Connection connection, DbAdapter adapter, DbLoaderDelegate 
delegate, ObjectNameGenerator strategy) {
-        this.adapter = adapter;
-        this.connection = connection;
+    public DbLoader(Connection connection, DbAdapter adapter, DbLoaderDelegate 
delegate, EntityMergeSupport entityMergeSupport) {
+        this.adapter = Objects.requireNonNull(adapter);
+        this.connection = Objects.requireNonNull(connection);
+        this.entityMergeSupport = Objects.requireNonNull(entityMergeSupport);
         this.delegate = delegate == null ? new DefaultDbLoaderDelegate() : 
delegate;
-
-        setNameGenerator(strategy);
     }
 
     private static List<String> getStrings(ResultSet rs) throws SQLException {
-        List<String> strings = new ArrayList<String>();
+        List<String> strings = new ArrayList<>();
 
         while (rs.next()) {
             strings.add(rs.getString(1));
@@ -110,8 +90,12 @@ public class DbLoader {
         return strings;
     }
 
-    private static Collection<ObjEntity> loadObjEntities(DataMap map, 
DbLoaderConfiguration config,
-                                                         Collection<DbEntity> 
entities, ObjectNameGenerator nameGenerator) {
+    private static Collection<ObjEntity> loadObjEntities(
+            DataMap map,
+            DbLoaderConfiguration config,
+            Collection<DbEntity> entities,
+            ObjectNameGenerator nameGenerator) {
+
         if (entities.isEmpty()) {
             return Collections.emptyList();
         }
@@ -156,7 +140,7 @@ public class DbLoader {
         if (loadedObjEntities.isEmpty()) {
             return;
         }
-        Collection<ObjEntity> entitiesForDelete = new LinkedList<ObjEntity>();
+        Collection<ObjEntity> entitiesForDelete = new LinkedList<>();
 
         for (ObjEntity curEntity : loadedObjEntities) {
             ManyToManyCandidateEntity entity = 
ManyToManyCandidateEntity.build(curEntity);
@@ -218,13 +202,6 @@ public class DbLoader {
     }
 
     /**
-     * @since 3.0
-     */
-    public void setCreatingMeaningfulPK(boolean creatingMeaningfulPK) {
-        this.creatingMeaningfulPK = creatingMeaningfulPK;
-    }
-
-    /**
      * Retrieves catalogs for the database associated with this DbLoader.
      *
      * @return List with the catalog names, empty Array if none found.
@@ -252,19 +229,14 @@ public class DbLoader {
      */
     Collection<ObjEntity> loadObjEntities(DataMap map, DbLoaderConfiguration 
config,
                                           Collection<DbEntity> entities) {
-        Collection<ObjEntity> loadedEntities = DbLoader.loadObjEntities(map, 
config, entities, nameGenerator);
+        Collection<ObjEntity> loadedEntities = DbLoader
+                .loadObjEntities(map, config, entities, 
entityMergeSupport.getNameGenerator());
 
-        createEntityMerger(map).synchronizeWithDbEntities(loadedEntities);
+        entityMergeSupport.synchronizeWithDbEntities(loadedEntities);
 
         return loadedEntities;
     }
 
-    /**
-     * @since 4.0
-     */
-    protected EntityMergeSupport createEntityMerger(DataMap map) {
-        return new EntityMergeSupport(map, nameGenerator, 
!creatingMeaningfulPK);
-    }
 
     protected void loadDbRelationships(DbLoaderConfiguration config, String 
catalog, String schema,
                                        List<DbEntity> tables) throws 
SQLException {
@@ -278,6 +250,8 @@ public class DbLoader {
             tablesMap.put(table.getName(), table);
         }
 
+        ObjectNameGenerator nameGenerator = 
entityMergeSupport.getNameGenerator();
+
         Map<String, Set<ExportedKey>> keys = loadExportedKeys(config, catalog, 
schema, tablesMap);
         for (Map.Entry<String, Set<ExportedKey>> entry : keys.entrySet()) {
             if (LOGGER.isDebugEnabled()) {
@@ -352,9 +326,9 @@ public class DbLoader {
 
             // TODO: can we avoid resetting the name twice? Do we need a 
placeholder name above?
             forwardRelationship.setName(NameBuilder
-                            .builder(forwardRelationship, pkEntity)
-                            .baseName(nameGenerator.dbRelationshipName(key, 
!isOneToOne))
-                            .name());
+                    .builder(forwardRelationship, pkEntity)
+                    .baseName(nameGenerator.dbRelationshipName(key, 
!isOneToOne))
+                    .name());
 
             if (delegate.dbRelationshipLoaded(fkEntity, reverseRelationship)) {
                 fkEntity.addRelationship(reverseRelationship);
@@ -519,7 +493,7 @@ public class DbLoader {
 
     private void prepareObjLayer(DataMap dataMap, DbLoaderConfiguration 
config, Collection<DbEntity> entities) {
         Collection<ObjEntity> loadedObjEntities = loadObjEntities(dataMap, 
config, entities);
-        flattenManyToManyRelationships(dataMap, loadedObjEntities, 
nameGenerator);
+        flattenManyToManyRelationships(dataMap, loadedObjEntities, 
entityMergeSupport.getNameGenerator());
         fireObjEntitiesAddedEvents(loadedObjEntities);
     }
 
@@ -697,18 +671,4 @@ public class DbLoader {
         }
         return procedures;
     }
-
-    /**
-     * Sets new naming strategy for reverse engineering
-     *
-     * @since 3.0
-     */
-    public void setNameGenerator(ObjectNameGenerator strategy) {
-        if (strategy == null) {
-            LOGGER.warn("Attempt to set null into NameGenerator. 
LegacyObjectNameGenerator will be used.");
-            this.nameGenerator = new LegacyObjectNameGenerator();
-        } else {
-            this.nameGenerator = strategy;
-        }
-    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/EntityMergeSupportIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/EntityMergeSupportIT.java
 
b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/EntityMergeSupportIT.java
index 8d304da..bc24100 100644
--- 
a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/EntityMergeSupportIT.java
+++ 
b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/merge/EntityMergeSupportIT.java
@@ -87,7 +87,7 @@ public class EntityMergeSupportIT extends MergeCase {
                objEntity2.setDbEntity(dbEntity2);
                map.addObjEntity(objEntity2);
 
-               assertTrue(new EntityMergeSupport(map, new 
DefaultObjectNameGenerator(), true)
+               assertTrue(new EntityMergeSupport(new 
DefaultObjectNameGenerator(), true, true)
                                
.synchronizeWithDbEntities(Arrays.asList(objEntity1, objEntity2)));
                assertNotNull(objEntity1.getAttribute("name"));
                assertNotNull(objEntity1.getRelationship("rel1To2"));

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderIT.java
 
b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderIT.java
index 930d696..fe46391 100644
--- 
a/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderIT.java
+++ 
b/cayenne-dbsync/src/test/java/org/apache/cayenne/dbsync/reverse/db/DbLoaderIT.java
@@ -19,16 +19,22 @@
 
 package org.apache.cayenne.dbsync.reverse.db;
 
-import org.apache.cayenne.dbsync.reverse.db.DbLoader;
-import org.apache.cayenne.dbsync.reverse.db.DbLoaderConfiguration;
-import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
-import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
-import org.apache.cayenne.dbsync.reverse.filters.TableFilter;
 import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dba.TypesMapping;
+import org.apache.cayenne.dbsync.merge.EntityMergeSupport;
+import org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator;
+import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
+import org.apache.cayenne.dbsync.reverse.filters.PatternFilter;
+import org.apache.cayenne.dbsync.reverse.filters.TableFilter;
 import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.map.*;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.DetectedDbEntity;
+import org.apache.cayenne.map.ObjAttribute;
+import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.unit.UnitDbAdapter;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
@@ -43,7 +49,11 @@ import java.sql.Types;
 import java.util.Collection;
 import java.util.List;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 @UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
 public class DbLoaderIT extends ServerCase {
@@ -61,8 +71,6 @@ public class DbLoaderIT extends ServerCase {
     @Inject
     private UnitDbAdapter accessStackAdapter;
 
-    private DbLoader loader;
-
     private Connection connection;
 
     private static String msgForTypeMismatch(DbAttribute origAttr, DbAttribute 
newAttr) {
@@ -82,7 +90,14 @@ public class DbLoaderIT extends ServerCase {
     @Before
     public void before() throws Exception {
         this.connection = 
dataSourceFactory.getSharedDataSource().getConnection();
-        this.loader = new DbLoader(connection, adapter, null);
+    }
+
+    private DbLoader createDbLoader(boolean meaningfulPK, boolean 
meaningfulFK) {
+        EntityMergeSupport emSupport = new EntityMergeSupport(new 
DefaultObjectNameGenerator(),
+                !meaningfulPK,
+                !meaningfulFK);
+
+        return new DbLoader(connection, adapter, null, emSupport);
     }
 
     @After
@@ -95,6 +110,8 @@ public class DbLoaderIT extends ServerCase {
 
         String tableLabel = adapter.tableTypeForTable();
 
+        DbLoader loader = createDbLoader(false, false);
+
         List<DetectedDbEntity> tables = loader.createTableLoader(null, null, 
TableFilter.everything())
                 .getDbEntities(TableFilter.everything(), new 
String[]{tableLabel});
 
@@ -115,6 +132,8 @@ public class DbLoaderIT extends ServerCase {
     @Test
     public void testGetTablesWithWrongCatalog() throws Exception {
 
+        DbLoader loader = createDbLoader(false, false);
+
         DbLoaderConfiguration config = new DbLoaderConfiguration();
         config.setFiltersConfig(
                 FiltersConfig.create("WRONG", null, TableFilter.everything(), 
PatternFilter.INCLUDE_NOTHING));
@@ -129,6 +148,8 @@ public class DbLoaderIT extends ServerCase {
     @Test
     public void testGetTablesWithWrongSchema() throws Exception {
 
+        DbLoader loader = createDbLoader(false, false);
+
         DbLoaderConfiguration config = new DbLoaderConfiguration();
         config.setFiltersConfig(
                 FiltersConfig.create(null, "WRONG", TableFilter.everything(), 
PatternFilter.INCLUDE_NOTHING));
@@ -143,11 +164,11 @@ public class DbLoaderIT extends ServerCase {
     @Test
     public void testLoadWithMeaningfulPK() throws Exception {
 
+        DbLoader loader = createDbLoader(true, false);
+
         DataMap map = new DataMap();
         String[] tableLabel = {adapter.tableTypeForTable()};
 
-        loader.setCreatingMeaningfulPK(true);
-
         List<DbEntity> entities = loader
                 .createTableLoader(null, null, TableFilter.everything())
                 .loadDbEntities(map, CONFIG, tableLabel);
@@ -168,6 +189,7 @@ public class DbLoaderIT extends ServerCase {
      */
     @Test
     public void testLoad() throws Exception {
+        DbLoader loader = createDbLoader(false, false);
 
         boolean supportsUnique = 
runtime.getDataDomain().getDataNodes().iterator().next().getAdapter()
                 .supportsUniqueConstraints();
@@ -223,7 +245,6 @@ public class DbLoaderIT extends ServerCase {
         }
 
         // *** TESTING THIS ***
-        loader.setCreatingMeaningfulPK(false);
         loader.loadObjEntities(map, CONFIG, entities);
 
         assertObjEntities(map);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
----------------------------------------------------------------------
diff --git 
a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
 
b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
index b5c2fa7..c371ee6 100644
--- 
a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
+++ 
b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
@@ -146,27 +146,16 @@ public class DbImportConfiguration {
         final NameFilter meaningfulPkFilter = NamePatternMatcher.build(logger, 
getMeaningfulPkTables(),
                 getMeaningfulPkTables() != null ? null : "*");
 
-        DbLoader loader = new DbLoader(connection, adapter, loaderDelegate) {
+        EntityMergeSupport emSupport = new 
EntityMergeSupport(getNameGenerator(), true, true) {
 
             @Override
-            protected EntityMergeSupport createEntityMerger(DataMap map) {
-                EntityMergeSupport emSupport = new EntityMergeSupport(map, 
DbImportConfiguration.this.getNameGenerator(), true) {
-
-                    @Override
-                    protected boolean removePK(DbEntity dbEntity) {
-                        return 
!meaningfulPkFilter.isIncluded(dbEntity.getName());
-                    }
-                };
-
-                
emSupport.setUsePrimitives(DbImportConfiguration.this.isUsePrimitives());
-                return emSupport;
+            protected boolean removePK(DbEntity dbEntity) {
+                return !meaningfulPkFilter.isIncluded(dbEntity.getName());
             }
         };
 
-
-        loader.setNameGenerator(getNameGenerator());
-
-        return loader;
+        emSupport.setUsingPrimitives(isUsePrimitives());
+        return new DbLoader(connection, adapter, loaderDelegate, emSupport);
     }
 
     public ObjectNameGenerator getNameGenerator() {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
----------------------------------------------------------------------
diff --git 
a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
 
b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
index 8f5ef79..6ec486e 100644
--- 
a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
+++ 
b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
@@ -110,6 +110,7 @@ public class DefaultDbImportAction implements 
DbImportAction {
         return reverse;
     }
 
+    @Override
     public void execute(DbImportConfiguration config) throws Exception {
 
         if (logger.isDebugEnabled()) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
 
b/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
index 98842a3..affe74e 100644
--- 
a/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
+++ 
b/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
@@ -29,6 +29,7 @@ import org.apache.cayenne.dbsync.merge.AddRelationshipToDb;
 import org.apache.cayenne.dbsync.merge.CreateTableToDb;
 import org.apache.cayenne.dbsync.merge.CreateTableToModel;
 import org.apache.cayenne.dbsync.merge.DefaultModelMergeDelegate;
+import org.apache.cayenne.dbsync.merge.EntityMergeSupport;
 import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider;
 import org.apache.cayenne.dbsync.merge.MergerToken;
 import org.apache.cayenne.dbsync.merge.builders.DataMapBuilder;
@@ -48,6 +49,7 @@ import org.apache.cayenne.resource.URLResource;
 import org.apache.cayenne.tools.configuration.ToolsModule;
 import org.apache.cayenne.util.Util;
 import org.apache.commons.logging.Log;
+import org.junit.Before;
 import org.junit.Test;
 import org.xml.sax.InputSource;
 
@@ -87,32 +89,45 @@ public class DefaultDbImportActionTest {
             return true;
         }
 
-               @Override
-               public boolean canRead() {
-                       return true;
-               }
-       };
+        @Override
+        public boolean canRead() {
+            return true;
+        }
+    };
+
+    private DbAdapter mockAdapter;
+    private Connection mockConnection;
+    private DbLoaderDelegate mockDelegate;
+    private EntityMergeSupport mockEmSupport;
+
+    @Before
+    public void before() {
+        mockAdapter = mock(DbAdapter.class);
+        mockConnection = mock(Connection.class);
+        mockDelegate = mock(DbLoaderDelegate.class);
+        mockEmSupport = mock(EntityMergeSupport.class);
+    }
 
-       @Test
-       public void testNewDataMapImport() throws Exception {
+    @Test
+    public void testNewDataMapImport() throws Exception {
 
-               DbLoader dbLoader = new DbLoader(null, null, null) {
-                       @Override
-                       public void load(DataMap dataMap, DbLoaderConfiguration 
config) throws SQLException {
-                               new 
DataMapBuilder(dataMap).withDbEntities(2).build();
-                       }
-               };
+        DbLoader dbLoader = new DbLoader(mockConnection, mockAdapter, 
mockDelegate, mockEmSupport) {
+            @Override
+            public void load(DataMap dataMap, DbLoaderConfiguration config) 
throws SQLException {
+                new DataMapBuilder(dataMap).withDbEntities(2).build();
+            }
+        };
 
         DbImportConfiguration params = mock(DbImportConfiguration.class);
         when(params.createLoader(any(DbAdapter.class), any(Connection.class), 
any(DbLoaderDelegate.class)))
                 .thenReturn(dbLoader);
 
-               when(params.createDataMap()).thenReturn(new 
DataMap("testImport"));
-               when(params.createMergeDelegate()).thenReturn(new 
DefaultModelMergeDelegate());
-               when(params.getDbLoaderConfig()).thenReturn(new 
DbLoaderConfiguration());
+        when(params.createDataMap()).thenReturn(new DataMap("testImport"));
+        when(params.createMergeDelegate()).thenReturn(new 
DefaultModelMergeDelegate());
+        when(params.getDbLoaderConfig()).thenReturn(new 
DbLoaderConfiguration());
 
-               final DataMap DATA_MAP = new DataMap();
-               
when(params.initializeDataMap(any(DataMap.class))).thenReturn(DATA_MAP);
+        final DataMap DATA_MAP = new DataMap();
+        
when(params.initializeDataMap(any(DataMap.class))).thenReturn(DATA_MAP);
 
         final boolean[] haveWeTriedToSave = {false};
         DefaultDbImportAction action = buildDbImportAction(new 
FileProjectSaver() {
@@ -120,19 +135,19 @@ public class DefaultDbImportActionTest {
             public void save(Project project) {
                 haveWeTriedToSave[0] = true;
 
-                               // Validation phase
-                               assertEquals(DATA_MAP, project.getRootNode());
-                       }
-               }, null);
+                // Validation phase
+                assertEquals(DATA_MAP, project.getRootNode());
+            }
+        }, null);
 
-               action.execute(params);
+        action.execute(params);
 
-               assertTrue("We should try to save.", haveWeTriedToSave[0]);
-       }
+        assertTrue("We should try to save.", haveWeTriedToSave[0]);
+    }
 
     @Test
     public void testImportWithFieldChanged() throws Exception {
-        DbLoader dbLoader = new DbLoader(null, null, null) {
+        DbLoader dbLoader = new DbLoader(mockConnection, mockAdapter, 
mockDelegate, mockEmSupport) {
             @Override
             public void load(DataMap dataMap, DbLoaderConfiguration config) 
throws SQLException {
                 new DataMapBuilder(dataMap).with(
@@ -146,17 +161,17 @@ public class DefaultDbImportActionTest {
                                 
objAttr("name").type(String.class).dbPath("NAME")
                         ));
             }
-               };
+        };
 
         DbImportConfiguration params = mock(DbImportConfiguration.class);
         when(params.createLoader(any(DbAdapter.class), any(Connection.class), 
any(DbLoaderDelegate.class)))
                 .thenReturn(dbLoader);
 
-               when(params.createDataMap()).thenReturn(new 
DataMap("testImport"));
-               when(params.getDataMapFile()).thenReturn(FILE_STUB);
-               when(params.createMergeDelegate()).thenReturn(new 
DefaultModelMergeDelegate());
-               when(params.getDbLoaderConfig()).thenReturn(new 
DbLoaderConfiguration());
-               when(params.getNameGenerator()).thenReturn(new 
DefaultObjectNameGenerator());
+        when(params.createDataMap()).thenReturn(new DataMap("testImport"));
+        when(params.getDataMapFile()).thenReturn(FILE_STUB);
+        when(params.createMergeDelegate()).thenReturn(new 
DefaultModelMergeDelegate());
+        when(params.getDbLoaderConfig()).thenReturn(new 
DbLoaderConfiguration());
+        when(params.getNameGenerator()).thenReturn(new 
DefaultObjectNameGenerator());
 
         final boolean[] haveWeTriedToSave = {false};
         DefaultDbImportAction action = buildDbImportAction(new 
FileProjectSaver() {
@@ -164,17 +179,17 @@ public class DefaultDbImportActionTest {
             public void save(Project project) {
                 haveWeTriedToSave[0] = true;
 
-                               // Validation phase
-                               DataMap rootNode = (DataMap) 
project.getRootNode();
-                               assertEquals(1, 
rootNode.getObjEntities().size());
-                               assertEquals(1, 
rootNode.getDbEntityMap().size());
+                // Validation phase
+                DataMap rootNode = (DataMap) project.getRootNode();
+                assertEquals(1, rootNode.getObjEntities().size());
+                assertEquals(1, rootNode.getDbEntityMap().size());
 
-                               DbEntity entity = 
rootNode.getDbEntity("ARTGROUP");
-                               assertNotNull(entity);
-                               assertEquals(4, entity.getAttributes().size());
-                               assertNotNull(entity.getAttribute("NAME_01"));
-                       }
-               }, new MapLoader() {
+                DbEntity entity = rootNode.getDbEntity("ARTGROUP");
+                assertNotNull(entity);
+                assertEquals(4, entity.getAttributes().size());
+                assertNotNull(entity.getAttribute("NAME_01"));
+            }
+        }, new MapLoader() {
 
             @Override
             public synchronized DataMap loadDataMap(InputSource src) throws 
CayenneRuntimeException {
@@ -190,14 +205,14 @@ public class DefaultDbImportActionTest {
             }
         });
 
-               action.execute(params);
+        action.execute(params);
 
-               assertTrue("We should try to save.", haveWeTriedToSave[0]);
-       }
+        assertTrue("We should try to save.", haveWeTriedToSave[0]);
+    }
 
     @Test
     public void testImportWithoutChanges() throws Exception {
-        DbLoader dbLoader = new DbLoader(null, null, null) {
+        DbLoader dbLoader = new DbLoader(mockConnection, mockAdapter, 
mockDelegate, mockEmSupport) {
             @Override
             public void load(DataMap dataMap, DbLoaderConfiguration config) 
throws SQLException {
                 new DataMapBuilder(dataMap).with(
@@ -205,23 +220,23 @@ public class DefaultDbImportActionTest {
                                 dbAttr("NAME").typeVarchar(100).mandatory()
                         ));
             }
-               };
+        };
 
         DbImportConfiguration params = mock(DbImportConfiguration.class);
         when(params.createLoader(any(DbAdapter.class), any(Connection.class), 
any(DbLoaderDelegate.class)))
                 .thenReturn(dbLoader);
 
-               when(params.createDataMap()).thenReturn(new 
DataMap("testImport"));
-               when(params.getDataMapFile()).thenReturn(FILE_STUB);
-               when(params.createMergeDelegate()).thenReturn(new 
DefaultModelMergeDelegate());
-               when(params.getDbLoaderConfig()).thenReturn(new 
DbLoaderConfiguration());
+        when(params.createDataMap()).thenReturn(new DataMap("testImport"));
+        when(params.getDataMapFile()).thenReturn(FILE_STUB);
+        when(params.createMergeDelegate()).thenReturn(new 
DefaultModelMergeDelegate());
+        when(params.getDbLoaderConfig()).thenReturn(new 
DbLoaderConfiguration());
 
-               Log log = mock(Log.class);
-               when(log.isDebugEnabled()).thenReturn(false);
-               when(log.isInfoEnabled()).thenReturn(false);
+        Log log = mock(Log.class);
+        when(log.isDebugEnabled()).thenReturn(false);
+        when(log.isInfoEnabled()).thenReturn(false);
 
-               FileProjectSaver projectSaver = mock(FileProjectSaver.class);
-               doNothing().when(projectSaver).save(any(Project.class));
+        FileProjectSaver projectSaver = mock(FileProjectSaver.class);
+        doNothing().when(projectSaver).save(any(Project.class));
 
         MapLoader mapLoader = mock(MapLoader.class);
         stub(mapLoader.loadDataMap(any(InputSource.class))).toReturn(new 
DataMapBuilder().with(
@@ -231,108 +246,108 @@ public class DefaultDbImportActionTest {
 
         DefaultDbImportAction action = buildDbImportAction(log, projectSaver, 
mapLoader);
 
-               action.execute(params);
+        action.execute(params);
 
-               verify(projectSaver, never()).save(any(Project.class));
-               verify(mapLoader, times(1)).loadDataMap(any(InputSource.class));
-       }
+        verify(projectSaver, never()).save(any(Project.class));
+        verify(mapLoader, times(1)).loadDataMap(any(InputSource.class));
+    }
 
-       @Test
-       public void testImportWithDbError() throws Exception {
-               DbLoader dbLoader = mock(DbLoader.class);
-               doThrow(new 
SQLException()).when(dbLoader).load(any(DataMap.class), 
any(DbLoaderConfiguration.class));
+    @Test
+    public void testImportWithDbError() throws Exception {
+        DbLoader dbLoader = mock(DbLoader.class);
+        doThrow(new SQLException()).when(dbLoader).load(any(DataMap.class), 
any(DbLoaderConfiguration.class));
 
         DbImportConfiguration params = mock(DbImportConfiguration.class);
         when(params.createLoader(any(DbAdapter.class), any(Connection.class), 
any(DbLoaderDelegate.class)))
                 .thenReturn(dbLoader);
 
-               FileProjectSaver projectSaver = mock(FileProjectSaver.class);
-               doNothing().when(projectSaver).save(any(Project.class));
+        FileProjectSaver projectSaver = mock(FileProjectSaver.class);
+        doNothing().when(projectSaver).save(any(Project.class));
 
-               MapLoader mapLoader = mock(MapLoader.class);
-               
when(mapLoader.loadDataMap(any(InputSource.class))).thenReturn(null);
+        MapLoader mapLoader = mock(MapLoader.class);
+        when(mapLoader.loadDataMap(any(InputSource.class))).thenReturn(null);
 
         DefaultDbImportAction action = buildDbImportAction(projectSaver, 
mapLoader);
 
-               try {
-                       action.execute(params);
-                       fail();
-               } catch (SQLException e) {
-                       // expected
-               }
+        try {
+            action.execute(params);
+            fail();
+        } catch (SQLException e) {
+            // expected
+        }
 
-               verify(projectSaver, never()).save(any(Project.class));
-               verify(mapLoader, never()).loadDataMap(any(InputSource.class));
-       }
+        verify(projectSaver, never()).save(any(Project.class));
+        verify(mapLoader, never()).loadDataMap(any(InputSource.class));
+    }
 
     private DefaultDbImportAction buildDbImportAction(FileProjectSaver 
projectSaver, MapLoader mapLoader) throws Exception {
         Log log = mock(Log.class);
         when(log.isDebugEnabled()).thenReturn(true);
         when(log.isInfoEnabled()).thenReturn(true);
 
-               return buildDbImportAction(log, projectSaver, mapLoader);
-       }
+        return buildDbImportAction(log, projectSaver, mapLoader);
+    }
 
     private DefaultDbImportAction buildDbImportAction(Log log, 
FileProjectSaver projectSaver, MapLoader mapLoader) throws Exception {
         DbAdapter dbAdapter = mock(DbAdapter.class);
 
-               DbAdapterFactory adapterFactory = mock(DbAdapterFactory.class);
-               
when(adapterFactory.createAdapter(any(DataNodeDescriptor.class), 
any(DataSource.class))).thenReturn(dbAdapter);
+        DbAdapterFactory adapterFactory = mock(DbAdapterFactory.class);
+        when(adapterFactory.createAdapter(any(DataNodeDescriptor.class), 
any(DataSource.class))).thenReturn(dbAdapter);
 
-               DataSourceFactory dataSourceFactory = 
mock(DataSourceFactory.class);
-               DataSource mock = mock(DataSource.class);
-               
when(dataSourceFactory.getDataSource(any(DataNodeDescriptor.class))).thenReturn(mock);
+        DataSourceFactory dataSourceFactory = mock(DataSourceFactory.class);
+        DataSource mock = mock(DataSource.class);
+        
when(dataSourceFactory.getDataSource(any(DataNodeDescriptor.class))).thenReturn(mock);
 
-               MergerTokenFactoryProvider mergerTokenFactoryProvider = 
mock(MergerTokenFactoryProvider.class);
-               
when(mergerTokenFactoryProvider.get(any(DbAdapter.class))).thenReturn(new 
DefaultMergerTokenFactory());
+        MergerTokenFactoryProvider mergerTokenFactoryProvider = 
mock(MergerTokenFactoryProvider.class);
+        
when(mergerTokenFactoryProvider.get(any(DbAdapter.class))).thenReturn(new 
DefaultMergerTokenFactory());
 
         return new DefaultDbImportAction(log, projectSaver, dataSourceFactory, 
adapterFactory, mapLoader, mergerTokenFactoryProvider);
     }
 
-       @Test
-       public void testSaveLoaded() throws Exception {
-               Log log = mock(Log.class);
-               Injector i = DIBootstrap.createInjector(new 
CayenneDbSyncModule(), new ToolsModule(log), new DbImportModule());
+    @Test
+    public void testSaveLoaded() throws Exception {
+        Log log = mock(Log.class);
+        Injector i = DIBootstrap.createInjector(new CayenneDbSyncModule(), new 
ToolsModule(log), new DbImportModule());
 
         DefaultDbImportAction action = (DefaultDbImportAction) 
i.getInstance(DbImportAction.class);
 
-               String packagePath = 
getClass().getPackage().getName().replace('.', '/');
-               URL packageUrl = 
getClass().getClassLoader().getResource(packagePath);
-               assertNotNull(packageUrl);
-               URL outUrl = new URL(packageUrl, 
"dbimport/testSaveLoaded1.map.xml");
+        String packagePath = getClass().getPackage().getName().replace('.', 
'/');
+        URL packageUrl = getClass().getClassLoader().getResource(packagePath);
+        assertNotNull(packageUrl);
+        URL outUrl = new URL(packageUrl, "dbimport/testSaveLoaded1.map.xml");
 
-               File out = new File(outUrl.toURI());
-               out.delete();
-               assertFalse(out.isFile());
+        File out = new File(outUrl.toURI());
+        out.delete();
+        assertFalse(out.isFile());
 
-               DataMap map = new DataMap("testSaveLoaded1");
-               map.setConfigurationSource(new URLResource(outUrl));
+        DataMap map = new DataMap("testSaveLoaded1");
+        map.setConfigurationSource(new URLResource(outUrl));
 
-               action.saveLoaded(map);
+        action.saveLoaded(map);
 
-               assertTrue(out.isFile());
+        assertTrue(out.isFile());
 
-               String contents = Util.stringFromFile(out);
-               assertTrue("Has no project version saved", 
contents.contains("project-version=\""));
-       }
+        String contents = Util.stringFromFile(out);
+        assertTrue("Has no project version saved", 
contents.contains("project-version=\""));
+    }
 
-       @Test
-       public void testMergeTokensSorting() {
-               LinkedList<MergerToken> tokens = new LinkedList<MergerToken>();
-               tokens.add(new AddColumnToDb(null, null));
-               tokens.add(new AddRelationshipToDb(null, null));
-               tokens.add(new CreateTableToDb(null));
-               tokens.add(new CreateTableToModel(null));
+    @Test
+    public void testMergeTokensSorting() {
+        LinkedList<MergerToken> tokens = new LinkedList<MergerToken>();
+        tokens.add(new AddColumnToDb(null, null));
+        tokens.add(new AddRelationshipToDb(null, null));
+        tokens.add(new CreateTableToDb(null));
+        tokens.add(new CreateTableToModel(null));
 
         assertEquals(asList("AddColumnToDb", "CreateTableToDb", 
"CreateTableToModel", "AddRelationshipToDb"),
                 toClasses(DefaultDbImportAction.sort(tokens)));
     }
 
-       private List<String> toClasses(List<MergerToken> sort) {
-               LinkedList<String> res = new LinkedList<String>();
-               for (MergerToken mergerToken : sort) {
-                       res.add(mergerToken.getClass().getSimpleName());
-               }
-               return res;
-       }
+    private List<String> toClasses(List<MergerToken> sort) {
+        LinkedList<String> res = new LinkedList<String>();
+        for (MergerToken mergerToken : sort) {
+            res.add(mergerToken.getClass().getSimpleName());
+        }
+        return res;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateObjEntityAction.java
----------------------------------------------------------------------
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateObjEntityAction.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateObjEntityAction.java
index b5a95d7..af43556 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateObjEntityAction.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateObjEntityAction.java
@@ -1,22 +1,21 @@
-/*****************************************************************
- *   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
+/*
+ *    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
  *
- *    http://www.apache.org/licenses/LICENSE-2.0
+ *      http://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.
- ****************************************************************/
-
+ *    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.modeler.action;
 
 import org.apache.cayenne.configuration.ConfigurationNode;
@@ -113,7 +112,7 @@ public class CreateObjEntityAction extends CayenneAction {
         dataMap.addObjEntity(entity);
 
         // perform the merge
-        EntityMergeSupport merger = new EntityMergeSupport(dataMap, new 
DefaultObjectNameGenerator(), true);
+        EntityMergeSupport merger = new EntityMergeSupport(new 
DefaultObjectNameGenerator(), true, true);
         
merger.addEntityMergeListener(DeleteRuleUpdater.getEntityMergeListener());
         merger.synchronizeWithDbEntity(entity);
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/DbEntitySyncAction.java
----------------------------------------------------------------------
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/DbEntitySyncAction.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/DbEntitySyncAction.java
index 65294b5..5a5f346 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/DbEntitySyncAction.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/DbEntitySyncAction.java
@@ -89,7 +89,7 @@ public class DbEntitySyncAction extends CayenneAction {
 
                                merger.addEntityMergeListener(listener);
 
-                               if (merger.isRemoveMeaningfulFKs()) {
+                               if (merger.isRemovingMeaningfulFKs()) {
                                        undoableEdit.addEdit(undoableEdit.new 
MeaningfulFKsUndoableEdit(entity, merger
                                                        
.getMeaningfulFKs(entity)));
                                }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/MigrateAction.java
----------------------------------------------------------------------
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/MigrateAction.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/MigrateAction.java
index b8e7383..a629477 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/MigrateAction.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/MigrateAction.java
@@ -20,7 +20,9 @@
 package org.apache.cayenne.modeler.action;
 
 import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.merge.EntityMergeSupport;
 import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider;
+import org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator;
 import org.apache.cayenne.dbsync.reverse.db.DbLoader;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.modeler.Application;
@@ -105,6 +107,8 @@ public class MigrateAction extends DBWizardAction {
                 .makeAdapter(getApplication().getClassLoadingService());
         DataSource dataSource = connectWizard.getConnectionInfo()
                 .makeDataSource(getApplication().getClassLoadingService());
-        return new DbLoader(dataSource.getConnection(), dbAdapter, 
null).loadSchemas();
+
+        EntityMergeSupport emSupport = new EntityMergeSupport(new 
DefaultObjectNameGenerator(), true, true);
+        return new DbLoader(dataSource.getConnection(), dbAdapter, null, 
emSupport).loadSchemas();
     }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
----------------------------------------------------------------------
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
index 7ee114c..5a3bbfb 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/DbLoaderHelper.java
@@ -62,10 +62,11 @@ import java.util.List;
 public class DbLoaderHelper {
 
     // TODO: this is a temp hack... need to delegate to DbAdapter, or
-    // configurable in
-    // preferences...
+    // configurable in preferences...
     private static final Collection<String> EXCLUDED_TABLES = 
Arrays.asList("AUTO_PK_SUPPORT", "auto_pk_support");
-    private static Log logObj = LogFactory.getLog(DbLoaderHelper.class);
+
+    private static Log LOGGER = LogFactory.getLog(DbLoaderHelper.class);
+
     protected boolean stoppingReverseEngineering;
     protected boolean existingMap;
 
@@ -91,7 +92,7 @@ public class DbLoaderHelper {
         try {
             this.dbCatalog = connection.getCatalog();
         } catch (SQLException e) {
-            logObj.warn("Error getting catalog.", e);
+            LOGGER.warn("Error getting catalog.", e);
         }
         this.adapter = adapter;
         this.reverseEngineering = reverseEngineering;
@@ -105,7 +106,7 @@ public class DbLoaderHelper {
         try {
             this.dbCatalog = connection.getCatalog();
         } catch (SQLException e) {
-            logObj.warn("Error getting catalog.", e);
+            LOGGER.warn("Error getting catalog.", e);
         }
         try {
             this.loader = config.createLoader(adapter, connection, new 
LoaderDelegate());
@@ -152,15 +153,12 @@ public class DbLoaderHelper {
             return;
         }
 
-        this.loader.setCreatingMeaningfulPK(true);
-
         LongRunningTask loadDataMapTask = new 
LoadDataMapTask(Application.getFrame(), "Reengineering DB");
         loadDataMapTask.startAndWait();
-
     }
 
     protected void processException(final Throwable th, final String message) {
-        logObj.info("Exception on reverse engineering", 
Util.unwindException(th));
+        LOGGER.info("Exception on reverse engineering", 
Util.unwindException(th));
         SwingUtilities.invokeLater(new Runnable() {
 
             public void run() {
@@ -369,11 +367,11 @@ public class DbLoaderHelper {
             
config.getDbLoaderConfig().setFiltersConfig(filtersConfigBuilder.build());
 
 
-            ModelerDbImportAction importAction = new 
ModelerDbImportAction(logObj, DbLoaderHelper.this);
+            ModelerDbImportAction importAction = new 
ModelerDbImportAction(LOGGER, DbLoaderHelper.this);
 
             // TODO: we can keep all these things in the Modeler Injector 
instead of creating a new one?
             // we already have CayenneDbSyncModule in there
-            Injector injector = DIBootstrap.createInjector(new 
CayenneDbSyncModule(), new ToolsModule(logObj), new DbImportModule());
+            Injector injector = DIBootstrap.createInjector(new 
CayenneDbSyncModule(), new ToolsModule(LOGGER), new DbImportModule());
             injector.injectMembers(importAction);
             try {
                 importAction.execute(config);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/ac04c11b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/ModelerDbLoader.java
----------------------------------------------------------------------
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/ModelerDbLoader.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/ModelerDbLoader.java
index 6ca30af..4a5f53e 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/ModelerDbLoader.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/db/ModelerDbLoader.java
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.cayenne.modeler.dialog.db;
 
+import org.apache.cayenne.dbsync.merge.EntityMergeSupport;
+import org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator;
 import org.apache.cayenne.dbsync.reverse.db.DbLoader;
 import org.apache.cayenne.dbsync.reverse.db.DbLoaderConfiguration;
 import org.apache.cayenne.dbsync.reverse.db.DefaultDbLoaderDelegate;
@@ -52,7 +54,10 @@ class ModelerDbLoader extends DbLoader {
     private ReverseEngineeringController reverseEngineeringController;
 
     public ModelerDbLoader(ReverseEngineeringController 
reverseEngineeringController, TreeEditor treeEditor, Connection connection) {
-        super(connection, reverseEngineeringController.adapter, new 
DefaultDbLoaderDelegate());
+        super(connection,
+                reverseEngineeringController.adapter,
+                new DefaultDbLoaderDelegate(),
+                new EntityMergeSupport(new DefaultObjectNameGenerator(), true, 
true));
         this.treeEditor = treeEditor;
         this.reverseEngineeringController = reverseEngineeringController;
     }

Reply via email to