cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kolonit...@apache.org
Subject [1/2] cayenne git commit: CAY-2003 cdbimport doesn't work properly with several includeTable tags Extract table and attributes loading logic into separate classes remove dependency to commons-lang
Date Mon, 27 Apr 2015 05:09:00 GMT
Repository: cayenne
Updated Branches:
  refs/heads/master cad4e03f0 -> a6b55f792


CAY-2003 cdbimport doesn't work properly with several includeTable tags
Extract table and attributes loading logic into separate classes
remove dependency to commons-lang


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

Branch: refs/heads/master
Commit: 50174debb4f8a5d4c68344b1618820ef94b7dc89
Parents: 09c6da9
Author: Alex Kolonitsky <Alex.Kolonitsky@gmail.com>
Authored: Mon Apr 27 08:07:53 2015 +0300
Committer: Alex Kolonitsky <Alex.Kolonitsky@gmail.com>
Committed: Mon Apr 27 08:07:53 2015 +0300

----------------------------------------------------------------------
 cayenne-server/pom.xml                          |   5 -
 .../org/apache/cayenne/access/DbLoader.java     | 417 ++++---------------
 .../access/loader/DbAttributesBaseLoader.java   | 107 +++++
 .../access/loader/DbAttributesLoader.java       |  43 ++
 .../loader/DbAttributesPerSchemaLoader.java     | 120 ++++++
 .../cayenne/access/loader/DbTableLoader.java    | 189 +++++++++
 .../org/apache/cayenne/access/DbLoaderIT.java   |  67 ++-
 7 files changed, 575 insertions(+), 373 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/50174deb/cayenne-server/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/pom.xml b/cayenne-server/pom.xml
index ee4e3c7..d00cd8c 100644
--- a/cayenne-server/pom.xml
+++ b/cayenne-server/pom.xml
@@ -48,11 +48,6 @@
 			<artifactId>commons-logging</artifactId>
 			<scope>compile</scope>
 		</dependency>
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-lang3</artifactId>
-            <version>3.0</version>
-        </dependency>
 		<dependency>
 			<groupId>org.apache.velocity</groupId>
 			<artifactId>velocity</artifactId>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/50174deb/cayenne-server/src/main/java/org/apache/cayenne/access/DbLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DbLoader.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DbLoader.java
index 1a2e24a..f2c473a 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DbLoader.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DbLoader.java
@@ -20,12 +20,13 @@ package org.apache.cayenne.access;
 
 import java.sql.*;
 import java.util.*;
-import java.util.regex.Pattern;
 
-import org.apache.cayenne.access.loader.DbLoaderConfiguration;
-import org.apache.cayenne.access.loader.DefaultDbLoaderDelegate;
-import org.apache.cayenne.access.loader.ManyToManyCandidateEntity;
-import org.apache.cayenne.access.loader.filters.*;
+import org.apache.cayenne.access.loader.*;
+import org.apache.cayenne.access.loader.filters.CatalogFilter;
+import org.apache.cayenne.access.loader.filters.FiltersConfig;
+import org.apache.cayenne.access.loader.filters.PatternFilter;
+import org.apache.cayenne.access.loader.filters.SchemaFilter;
+import org.apache.cayenne.access.loader.filters.TableFilter;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.map.DataMap;
@@ -34,7 +35,6 @@ import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbJoin;
 import org.apache.cayenne.map.DbRelationship;
 import org.apache.cayenne.map.DbRelationshipDetected;
-import org.apache.cayenne.map.DetectedDbEntity;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.Procedure;
 import org.apache.cayenne.map.ProcedureParameter;
@@ -45,7 +45,6 @@ import org.apache.cayenne.map.naming.NameCheckers;
 import org.apache.cayenne.map.naming.ObjectNameGenerator;
 import org.apache.cayenne.util.EntityMergeSupport;
 import org.apache.cayenne.util.EqualsBuilder;
-import org.apache.commons.lang3.tuple.Pair;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -192,245 +191,6 @@ public class DbLoader {
     }
 
     /**
-     * Returns all tables for given combination of the criteria. Tables returned
-     * as DbEntities without any attributes or relationships.
-     *
-     * @param config
-     * @param types  The types of table names to retrieve, null returns all types.
-     * @return
-     * @since 4.0
-     */
-    public Map<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>> getTables(DbLoaderConfiguration config, String[] types)
-            throws SQLException {
-        if (types == null || types.length == 0) {
-            types = getDefaultTableTypes();
-        }
-
-        Map<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>> tables = new HashMap<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>>();
-        FiltersConfig filters = config.getFiltersConfig();
-        for (CatalogFilter catalog : filters.catalogs) {
-            for (SchemaFilter schema : catalog.schemas) {
-                Pair<String, String> path = Pair.of(catalog.name, schema.name);
-                Map<String, Pair<DbEntity, PatternFilter>> dbEntities = getDbEntities(filters, path, types);
-                if (!dbEntities.isEmpty()) {
-                    tables.put(path, dbEntities);
-                }
-            }
-        }
-
-        return tables;
-    }
-
-    /**
-     * @param filters
-     * @param dbPath
-     * @param types
-     * @return Map<TableName, DbEntity>
-     * @throws SQLException
-     */
-    private Map<String, Pair<DbEntity, PatternFilter>> getDbEntities(FiltersConfig filters, Pair<String, String> dbPath, String[] types) throws SQLException {
-        if (LOGGER.isDebugEnabled()) {
-            LOGGER.debug("Read tables: catalog=" + dbPath.getKey() + ", schema=" + dbPath.getValue() + ", types="
-                    + Arrays.toString(types));
-        }
-
-        ResultSet rs = getMetaData().getTables(dbPath.getKey(), dbPath.getValue(), WILDCARD, types);
-
-        Map<String, Pair<DbEntity, PatternFilter>> tables = new HashMap<String, Pair<DbEntity, PatternFilter>>();
-        try {
-            while (rs.next()) {
-                // Oracle 9i and newer has a nifty recycle bin feature... but we don't
-                // want dropped tables to be included here; in fact they may even result
-                // in errors on reverse engineering as their names have special chars like
-                // "/", etc. So skip them all together
-
-                String name = rs.getString("TABLE_NAME");
-                if (name == null) {
-                    continue;
-                }
-
-                DbEntity table = new DetectedDbEntity(name);
-
-                String catalog = rs.getString("TABLE_CAT");
-                table.setCatalog(catalog);
-
-                String schema = rs.getString("TABLE_SCHEM");
-                table.setSchema(schema);
-
-                PatternFilter includeTable = filters.tableFilter(catalog, schema).isIncludeTable(table.getName());
-                if (includeTable != null) {
-                    tables.put(name, Pair.of(table, includeTable));
-                }
-            }
-        } finally {
-            rs.close();
-        }
-        return tables;
-    }
-
-    /**
-     * Loads dbEntities for the specified tables.
-     *  @param map    DataMap to be populated with DbEntities.
-     * @param config
-     * @param tables The list of org.apache.cayenne.ashwood.dbutil.Table objects
-     */
-    public List<DbEntity> loadDbEntities(DataMap map, DbLoaderConfiguration config, Map<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>> tables) throws SQLException {
-        /** List of db entities to process. */
-
-        List<DbEntity> dbEntityList = new ArrayList<DbEntity>();
-        for (Map.Entry<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>> tablesMap : tables.entrySet()) {
-            for (Pair<DbEntity, PatternFilter> dbEntity : tablesMap.getValue().values()) {
-
-                // Check if there already is a DbEntity under such name
-                // if so, consult the delegate what to do
-                DbEntity oldEnt = map.getDbEntity(dbEntity.getKey().getName());
-                if (oldEnt != null) {
-                    Collection<ObjEntity> oldObjEnt = map.getMappedEntities(oldEnt);
-                    if (!oldObjEnt.isEmpty()) {
-                        for (ObjEntity objEntity : oldObjEnt) {
-                            LOGGER.debug("Delete ObjEntity: " + objEntity.getName());
-                            map.removeObjEntity(objEntity.getName(), true);
-                            delegate.objEntityRemoved(objEntity);
-                        }
-                    }
-
-                    LOGGER.debug("Overwrite DbEntity: " + oldEnt.getName());
-                    map.removeDbEntity(oldEnt.getName(), true);
-                    delegate.dbEntityRemoved(oldEnt);
-                }
-
-                map.addDbEntity(dbEntity.getKey());
-
-                delegate.dbEntityAdded(dbEntity.getKey());
-
-                // delegate might have thrown this entity out... so check if it is still
-                // around before continuing processing
-                if (map.getDbEntity(dbEntity.getKey().getName()) == dbEntity.getKey()) {
-                    dbEntityList.add(dbEntity.getKey());
-                }
-            }
-
-            loadDbAttributes(config.getFiltersConfig(), tablesMap.getKey(), tablesMap.getValue());
-
-            if (!config.isSkipPrimaryKeyLoading()) {
-                getPrimaryKeyForTable(tablesMap.getValue());
-            }
-        }
-
-        return dbEntityList;
-    }
-
-    private void getPrimaryKeyForTable(Map<String, Pair<DbEntity, PatternFilter>> tables) throws SQLException {
-        for (Pair<DbEntity, PatternFilter> pair : tables.values()) {
-            DbEntity dbEntity = pair.getKey();
-            ResultSet rs = getMetaData().getPrimaryKeys(dbEntity.getCatalog(), dbEntity.getSchema(), dbEntity.getName());
-            try {
-                while (rs.next()) {
-                    String columnName = rs.getString("COLUMN_NAME");
-                    DbAttribute attribute = dbEntity.getAttribute(columnName);
-
-                    if (attribute != null) {
-                        attribute.setPrimaryKey(true);
-                    } else {
-                        // why an attribute might be null is not quiet clear
-                        // but there is a bug report 731406 indicating that it is possible
-                        // so just print the warning, and ignore
-                        LOGGER.warn("Can't locate attribute for primary key: " + columnName);
-                    }
-
-                    String pkName = rs.getString("PK_NAME");
-                    if (pkName != null && dbEntity instanceof DetectedDbEntity) {
-                        ((DetectedDbEntity) dbEntity).setPrimaryKeyName(pkName);
-                    }
-
-                }
-            } finally {
-                rs.close();
-            }
-        }
-    }
-
-    private void loadDbAttributes(FiltersConfig filters, Pair<String, String> path, Map<String, Pair<DbEntity, PatternFilter>> entities) throws SQLException {
-        ResultSet rs = getMetaData().getColumns(path.getKey(), path.getValue(), WILDCARD, WILDCARD);
-
-        try {
-            Set<String> columns = new HashSet<String>();
-
-            while (rs.next()) {
-                // for a reason not quiet apparent to me, Oracle sometimes
-                // returns duplicate record sets for the same table, messing up table
-                // names. E.g. for the system table "WK$_ATTR_MAPPING" columns are
-                // returned twice - as "WK$_ATTR_MAPPING" and "WK$$_ATTR_MAPPING"... Go figure
-                String tableName = rs.getString("TABLE_NAME");
-                Pair<DbEntity, PatternFilter> pair = entities.get(tableName);
-                if (pair == null) {
-                    if (LOGGER.isDebugEnabled()) {
-                        LOGGER.debug("Skip column for '" + tableName + "." + rs.getString("COLUMN_NAME") + ".");
-                    }
-                    continue;
-                }
-                DbEntity dbEntity = pair.getKey();
-
-                DbAttribute attr = loadDbAttribute(columns, rs);
-                attr.setEntity(dbEntity);
-                if (!pair.getValue().isInclude(attr.getName())) {
-                    if (LOGGER.isDebugEnabled()) {
-                        LOGGER.debug("Skip column for '" + attr.getEntity().getName() + "." + attr.getName()
-                                + "' (Path: " + path + "; Filter: " + pair.getValue() + ")");
-                    }
-                    continue;
-                }
-
-                // override existing attributes if it comes again
-                if (dbEntity.getAttribute(attr.getName()) != null) {
-                    dbEntity.removeAttribute(attr.getName());
-                }
-                dbEntity.addAttribute(attr);
-            }
-        } finally {
-            rs.close();
-        }
-    }
-
-    private DbAttribute loadDbAttribute(Set<String> columns, ResultSet rs) throws SQLException {
-        if (columns.isEmpty()) {
-            ResultSetMetaData rsMetaData = rs.getMetaData();
-            for (int i = 1; i <= rsMetaData.getColumnCount(); i++) {
-                columns.add(rsMetaData.getColumnLabel(i));
-            }
-        }
-
-        // gets attribute's (column's) information
-        int columnType = rs.getInt("DATA_TYPE");
-
-        // ignore precision of non-decimal columns
-        int decimalDigits = -1;
-        if (TypesMapping.isDecimal(columnType)) {
-            decimalDigits = rs.getInt("DECIMAL_DIGITS");
-            if (rs.wasNull()) {
-                decimalDigits = -1;
-            }
-        }
-
-        // create attribute delegating this task to adapter
-        DbAttribute attr = adapter.buildAttribute(
-                rs.getString("COLUMN_NAME"),
-                rs.getString("TYPE_NAME"),
-                columnType,
-                rs.getInt("COLUMN_SIZE"),
-                decimalDigits,
-                rs.getBoolean("NULLABLE"));
-
-        if (columns.contains("IS_AUTOINCREMENT")) {
-            String autoIncrement = rs.getString("IS_AUTOINCREMENT");
-            if ("YES".equals(autoIncrement)) {
-                attr.setGenerated(true);
-            }
-        }
-        return attr;
-    }
-
-    /**
      * Creates an ObjEntity for each DbEntity in the map.
      */
     public Collection<ObjEntity> loadObjEntities(DataMap map, DbLoaderConfiguration config, Collection<DbEntity> entities) {
@@ -483,81 +243,83 @@ public class DbLoader {
         return new EntityMergeSupport(map, nameGenerator, !creatingMeaningfulPK);
     }
 
-    protected void loadDbRelationships(DbLoaderConfiguration config, Map<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>> tables) throws SQLException {
+    protected void loadDbRelationships(DbLoaderConfiguration config, String catalog, String schema, List<DbEntity> tables) throws SQLException {
         if (config.isSkipRelationshipsLoading()) {
             return;
         }
 
         // Get all the foreign keys referencing this table
+        Map<String, DbEntity> tablesMap = new HashMap<String, DbEntity>();
+        for (DbEntity table : tables) {
+            tablesMap.put(table.getName(), table);
+        }
 
-        for (Map.Entry<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>> pathEntry : tables.entrySet()) {
-            Map<String, Set<ExportedKey>> keys = loadExportedKeys(config, pathEntry.getKey(), pathEntry.getValue());
-            for (Map.Entry<String, Set<ExportedKey>> entry : keys.entrySet()) {
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("Process keys for: " + entry.getKey());
-                }
+        Map<String, Set<ExportedKey>> keys = loadExportedKeys(config, catalog, schema, tablesMap);
+        for (Map.Entry<String, Set<ExportedKey>> entry : keys.entrySet()) {
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug("Process keys for: " + entry.getKey());
+            }
 
-                Set<ExportedKey> exportedKeys = entry.getValue();
-                ExportedKey key = exportedKeys.iterator().next();
-                if (key == null) {
-                    throw new IllegalStateException();
-                }
+            Set<ExportedKey> exportedKeys = entry.getValue();
+            ExportedKey key = exportedKeys.iterator().next();
+            if (key == null) {
+                throw new IllegalStateException();
+            }
 
-                DbEntity pkEntity = pathEntry.getValue().get(key.getPKTableName()).getKey();
-                if (pkEntity == null) {
-                    skipRelationLog(key, key.getPKTableName());
-                    continue;
-                }
+            DbEntity pkEntity = tablesMap.get(key.getPKTableName());
+            if (pkEntity == null) {
+                skipRelationLog(key, key.getPKTableName());
+                continue;
+            }
 
-                DbEntity fkEntity = pathEntry.getValue().get(key.getFKTableName()).getKey();
-                if (fkEntity == null) {
-                    skipRelationLog(key, key.getFKTableName());
-                    continue;
-                }
+            DbEntity fkEntity = tablesMap.get(key.getFKTableName());
+            if (fkEntity == null) {
+                skipRelationLog(key, key.getFKTableName());
+                continue;
+            }
 
-                if (!new EqualsBuilder()
-                        .append(pkEntity.getCatalog(), key.pkCatalog)
-                        .append(pkEntity.getSchema(), key.pkSchema)
-                        .append(fkEntity.getCatalog(), key.fkCatalog)
-                        .append(fkEntity.getSchema(), key.fkSchema)
-                        .isEquals()) {
-
-                    LOGGER.info("Skip relation: '" + key + "' because it related to objects from other catalog/schema");
-                    LOGGER.info("     relation primary key: '" + key.pkCatalog + "." + key.pkSchema + "'");
-                    LOGGER.info("       primary key entity: '" + pkEntity.getCatalog() + "." + pkEntity.getSchema() + "'");
-                    LOGGER.info("     relation foreign key: '" + key.fkCatalog + "." + key.fkSchema + "'");
-                    LOGGER.info("       foreign key entity: '" + fkEntity.getCatalog() + "." + fkEntity.getSchema() + "'");
-                    continue;
-                }
+            if (!new EqualsBuilder()
+                    .append(pkEntity.getCatalog(), key.pkCatalog)
+                    .append(pkEntity.getSchema(), key.pkSchema)
+                    .append(fkEntity.getCatalog(), key.fkCatalog)
+                    .append(fkEntity.getSchema(), key.fkSchema)
+                    .isEquals()) {
+
+                LOGGER.info("Skip relation: '" + key + "' because it related to objects from other catalog/schema");
+                LOGGER.info("     relation primary key: '" + key.pkCatalog + "." + key.pkSchema + "'");
+                LOGGER.info("       primary key entity: '" + pkEntity.getCatalog() + "." + pkEntity.getSchema() + "'");
+                LOGGER.info("     relation foreign key: '" + key.fkCatalog + "." + key.fkSchema + "'");
+                LOGGER.info("       foreign key entity: '" + fkEntity.getCatalog() + "." + fkEntity.getSchema() + "'");
+                continue;
+            }
 
-                // forwardRelationship is a reference from table with primary key
-                DbRelationship forwardRelationship = new DbRelationship(generateName(pkEntity, key, true));
-                forwardRelationship.setSourceEntity(pkEntity);
-                forwardRelationship.setTargetEntityName(fkEntity);
+            // forwardRelationship is a reference from table with primary key
+            DbRelationship forwardRelationship = new DbRelationship(generateName(pkEntity, key, true));
+            forwardRelationship.setSourceEntity(pkEntity);
+            forwardRelationship.setTargetEntityName(fkEntity);
 
-                // forwardRelationship is a reference from table with foreign key, it is what exactly we load from db
-                DbRelationshipDetected reverseRelationship = new DbRelationshipDetected(generateName(fkEntity, key, false));
-                reverseRelationship.setFkName(key.getFKName());
-                reverseRelationship.setSourceEntity(fkEntity);
-                reverseRelationship.setTargetEntityName(pkEntity);
-                reverseRelationship.setToMany(false);
+            // forwardRelationship is a reference from table with foreign key, it is what exactly we load from db
+            DbRelationshipDetected reverseRelationship = new DbRelationshipDetected(generateName(fkEntity, key, false));
+            reverseRelationship.setFkName(key.getFKName());
+            reverseRelationship.setSourceEntity(fkEntity);
+            reverseRelationship.setTargetEntityName(pkEntity);
+            reverseRelationship.setToMany(false);
 
-                createAndAppendJoins(exportedKeys, pkEntity, fkEntity, forwardRelationship, reverseRelationship);
+            createAndAppendJoins(exportedKeys, pkEntity, fkEntity, forwardRelationship, reverseRelationship);
 
-                boolean toDependentPK = isToDependentPK(forwardRelationship);
-                forwardRelationship.setToDependentPK(toDependentPK);
+            boolean toDependentPK = isToDependentPK(forwardRelationship);
+            forwardRelationship.setToDependentPK(toDependentPK);
 
-                boolean isOneToOne = toDependentPK && fkEntity.getPrimaryKeys().size() == forwardRelationship.getJoins().size();
+            boolean isOneToOne = toDependentPK && fkEntity.getPrimaryKeys().size() == forwardRelationship.getJoins().size();
 
-                forwardRelationship.setToMany(!isOneToOne);
-                forwardRelationship.setName(generateName(pkEntity, key, !isOneToOne));
+            forwardRelationship.setToMany(!isOneToOne);
+            forwardRelationship.setName(generateName(pkEntity, key, !isOneToOne));
 
-                if (delegate.dbRelationshipLoaded(fkEntity, reverseRelationship)) {
-                    fkEntity.addRelationship(reverseRelationship);
-                }
-                if (delegate.dbRelationshipLoaded(pkEntity, forwardRelationship)) {
-                    pkEntity.addRelationship(forwardRelationship);
-                }
+            if (delegate.dbRelationshipLoaded(fkEntity, reverseRelationship)) {
+                fkEntity.addRelationship(reverseRelationship);
+            }
+            if (delegate.dbRelationshipLoaded(pkEntity, forwardRelationship)) {
+                pkEntity.addRelationship(forwardRelationship);
             }
         }
     }
@@ -596,21 +358,20 @@ public class DbLoader {
         }
     }
 
-    private Map<String, Set<ExportedKey>> loadExportedKeys(DbLoaderConfiguration config, Pair<String, String> dbPath, Map<String, Pair<DbEntity, PatternFilter>> tables) throws SQLException {
+    private Map<String, Set<ExportedKey>> loadExportedKeys(DbLoaderConfiguration config, String catalog, String schema, Map<String, DbEntity> tables) throws SQLException {
         Map<String, Set<ExportedKey>> keys = new HashMap<String, Set<ExportedKey>>();
 
-        for (Pair<DbEntity, PatternFilter> pair : tables.values()) {
-            DbEntity dbEntity = pair.getKey();
+        for (DbEntity dbEntity : tables.values()) {
             if (!delegate.dbRelationship(dbEntity)) {
                 continue;
             }
 
             ResultSet rs;
             try {
-                rs = getMetaData().getExportedKeys(dbPath.getKey(), dbPath.getValue(), dbEntity.getName());
+                rs = getMetaData().getExportedKeys(catalog, schema, dbEntity.getName());
             } catch (SQLException cay182Ex) {
                 // Sybase-specific - the line above blows on VIEWS, see CAY-182.
-                LOGGER.info("Error getting relationships for '" + dbPath + "', ignoring. "
+                LOGGER.info("Error getting relationships for '" + catalog + "." + schema + "', ignoring. "
                         + cay182Ex.getMessage(), cay182Ex);
                 return new HashMap<String, Set<ExportedKey>>();
             }
@@ -619,13 +380,12 @@ public class DbLoader {
                 while (rs.next()) {
                     ExportedKey key = ExportedKey.extractData(rs);
 
-                    Pair<DbEntity, PatternFilter> p = tables.get(key.getFKTableName());
-                    if (p == null) {
+                    DbEntity fkEntity = tables.get(key.getFKTableName());
+                    if (fkEntity == null) {
                         skipRelationLog(key, key.getFKTableName());
                         continue;
                     }
 
-                    DbEntity fkEntity = p.getKey();
                     if (config.getFiltersConfig().tableFilter(fkEntity.getCatalog(), fkEntity.getSchema()).isIncludeTable(fkEntity.getName()) == null) {
                         continue;
                     }
@@ -659,14 +419,6 @@ public class DbLoader {
     }
 
     /**
-     * Detects correct relationship multiplicity and "to dep pk" flag. Only
-     * called on relationships from PK to FK, not the reverse ones.
-     */
-    protected void postProcessMasterDbRelationship(DbRelationship relationship, ExportedKey key) {
-
-    }
-
-    /**
      * Flattens many-to-many relationships in the generated model.
      */
     public static void flattenManyToManyRelationships(DataMap map, Collection<ObjEntity> loadedObjEntities, ObjectNameGenerator objectNameGenerator) {
@@ -776,16 +528,31 @@ public class DbLoader {
     public void load(DataMap dataMap, DbLoaderConfiguration config) throws SQLException {
         LOGGER.info("Schema loading...");
 
-        Map<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>> tables = getTables(config, config.getTableTypes());
-        List<DbEntity> entities = loadDbEntities(dataMap, config, tables);
+        String[] types = config.getTableTypes();
+        if (types == null || types.length == 0) {
+            types = getDefaultTableTypes();
+        }
 
-        if (entities != null) {
-            loadDbRelationships(config, tables);
+        for (CatalogFilter catalog : config.getFiltersConfig().catalogs) {
+            for (SchemaFilter schema : catalog.schemas) {
+
+                List<DbEntity> entities = createTableLoader(catalog.name, schema.name, schema.tables)
+                        .loadDbEntities(dataMap, config, types);
+
+                if (entities != null) {
+                    loadDbRelationships(config, catalog.name, schema.name, entities);
 
-            prepareObjLayer(dataMap, config, entities);
+                    prepareObjLayer(dataMap, config, entities);
+                }
+            }
         }
     }
 
+    protected DbTableLoader createTableLoader(String catalog, String schema, TableFilter filter) throws SQLException {
+        return new DbTableLoader(catalog, schema, getMetaData(), delegate,
+                new DbAttributesPerSchemaLoader(catalog, schema, getMetaData(), adapter, filter));
+    }
+
     public void prepareObjLayer(DataMap dataMap, DbLoaderConfiguration config, Collection<DbEntity> entities) {
         Collection<ObjEntity> loadedObjEntities = loadObjEntities(dataMap, config, entities);
         flattenManyToManyRelationships(dataMap, loadedObjEntities, getNameGenerator());

http://git-wip-us.apache.org/repos/asf/cayenne/blob/50174deb/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesBaseLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesBaseLoader.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesBaseLoader.java
new file mode 100644
index 0000000..57e35ac
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesBaseLoader.java
@@ -0,0 +1,107 @@
+/*****************************************************************
+ *   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
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.access.loader;
+
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dba.TypesMapping;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Set;
+
+/**
+* @since 4.0.
+*/
+public abstract class DbAttributesBaseLoader implements DbAttributesLoader {
+    private final String catalog;
+    private final String schema;
+
+    private final DatabaseMetaData metaData;
+    private final DbAdapter adapter;
+
+    public DbAttributesBaseLoader(String catalog, String schema, DatabaseMetaData metaData, DbAdapter adapter) {
+        this.catalog = catalog;
+        this.schema = schema;
+        this.metaData = metaData;
+        this.adapter = adapter;
+    }
+
+    protected DbAttribute loadDbAttribute(Set<String> columns, ResultSet rs) throws SQLException {
+
+        // gets attribute's (column's) information
+        int columnType = rs.getInt("DATA_TYPE");
+
+        // ignore precision of non-decimal columns
+        int decimalDigits = -1;
+        if (TypesMapping.isDecimal(columnType)) {
+            decimalDigits = rs.getInt("DECIMAL_DIGITS");
+            if (rs.wasNull()) {
+                decimalDigits = -1;
+            }
+        }
+
+        // create attribute delegating this task to adapter
+        DbAttribute attr = adapter.buildAttribute(
+                rs.getString("COLUMN_NAME"),
+                rs.getString("TYPE_NAME"),
+                columnType,
+                rs.getInt("COLUMN_SIZE"),
+                decimalDigits,
+                rs.getBoolean("NULLABLE"));
+
+        if (columns.contains("IS_AUTOINCREMENT")) {
+            String autoIncrement = rs.getString("IS_AUTOINCREMENT");
+            if ("YES".equals(autoIncrement)) {
+                attr.setGenerated(true);
+            }
+        }
+        return attr;
+    }
+
+    @Override
+    public void loadDbAttributes(DbEntity entity) {
+        for (DbAttribute attr : loadDbAttributes(entity.getName())) {
+            attr.setEntity(entity);
+
+            // override existing attributes if it comes again
+            if (entity.getAttribute(attr.getName()) != null) {
+                entity.removeAttribute(attr.getName());
+            }
+            entity.addAttribute(attr);
+        }
+    }
+
+    protected abstract List<DbAttribute> loadDbAttributes(String tableName);
+
+    protected String getCatalog() {
+        return catalog;
+    }
+
+    protected String getSchema() {
+        return schema;
+    }
+
+    protected DatabaseMetaData getMetaData() {
+        return metaData;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/50174deb/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesLoader.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesLoader.java
new file mode 100644
index 0000000..e4113b4
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesLoader.java
@@ -0,0 +1,43 @@
+/*****************************************************************
+ *   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
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.access.loader;
+
+import org.apache.cayenne.map.DbEntity;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Interface responsible for attributes loading. Several options possible here
+ *  1) load attributes for each table separately
+ *  2) load attributes for schema and group it by table names
+ *
+ *  here is a trade of between count of queries and amount af calculation.
+ *
+ *
+ * @since 4.0
+ */
+public interface DbAttributesLoader {
+
+    // TODO use instant field for logging
+    Log LOGGER = LogFactory.getLog(DbTableLoader.class);
+
+    void loadDbAttributes(DbEntity entity);
+
+}
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/50174deb/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesPerSchemaLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesPerSchemaLoader.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesPerSchemaLoader.java
new file mode 100644
index 0000000..b32c230
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbAttributesPerSchemaLoader.java
@@ -0,0 +1,120 @@
+/*****************************************************************
+ *   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
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.access.loader;
+
+import org.apache.cayenne.access.loader.filters.PatternFilter;
+import org.apache.cayenne.access.loader.filters.TableFilter;
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.map.DbAttribute;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.*;
+
+/**
+ * Load all attributes for schema and return it for each table
+ * */
+public class DbAttributesPerSchemaLoader extends DbAttributesBaseLoader {
+
+    private final TableFilter filter;
+
+    private Map<String, List<DbAttribute>> attributes;
+
+    public DbAttributesPerSchemaLoader(String catalog, String schema, DatabaseMetaData metaData,
+                                       DbAdapter adapter, TableFilter filter) {
+        super(catalog, schema, metaData, adapter);
+
+        this.filter = filter;
+    }
+
+    private Map<String, List<DbAttribute>> loadDbAttributes() throws SQLException {
+        Map<String, List<DbAttribute>> attributes = new HashMap<String, List<DbAttribute>>();
+        ResultSet rs = getMetaData().getColumns(getCatalog(), getSchema(), "%", "%");
+        try {
+            Set<String> columns = new HashSet<String>();
+
+            while (rs.next()) {
+                if (columns.isEmpty()) {
+                    ResultSetMetaData rsMetaData = rs.getMetaData();
+                    for (int i = 1; i <= rsMetaData.getColumnCount(); i++) {
+                        columns.add(rsMetaData.getColumnLabel(i));
+                    }
+                }
+
+                // for a reason not quiet apparent to me, Oracle sometimes
+                // returns duplicate record sets for the same table, messing up table
+                // names. E.g. for the system table "WK$_ATTR_MAPPING" columns are
+                // returned twice - as "WK$_ATTR_MAPPING" and "WK$$_ATTR_MAPPING"... Go figure
+                String tableName = rs.getString("TABLE_NAME");
+                String columnName = rs.getString("COLUMN_NAME");
+
+                PatternFilter columnFilter = filter.isIncludeTable(tableName);
+                /*
+                * Here is possible optimization if filter will contain map<tableName, columnFilter>
+                *     we can replace it after tables loading since already done pattern matching once and exactly
+                *     know all tables that we want to process
+                * */
+                if (columnFilter == null || !columnFilter.isInclude(columnName)) {
+                    if (LOGGER.isDebugEnabled()) {
+                        LOGGER.debug("Skip column '" + tableName + "." + columnName
+                                + "' (Path: " + getCatalog() + "/" + getSchema() + "; Filter: " + columnFilter + ")");
+                    }
+                    continue;
+                }
+
+                List<DbAttribute> attrs = attributes.get(tableName);
+                if (attrs == null) {
+                    attrs = new LinkedList<DbAttribute>();
+
+                    attributes.put(tableName, attrs);
+                }
+
+                attrs.add(loadDbAttribute(columns, rs));
+            }
+        } finally {
+            rs.close();
+        }
+
+        return attributes;
+    }
+
+    @Override
+    protected List<DbAttribute> loadDbAttributes(String tableName) {
+        Map<String, List<DbAttribute>> attributes = getAttributes();
+        if (attributes != null) {
+            return attributes.get(tableName);
+        }
+
+        return new LinkedList<DbAttribute>();
+    }
+
+    public Map<String, List<DbAttribute>> getAttributes() {
+        if (attributes == null) {
+            try {
+                attributes = loadDbAttributes();
+            } catch (SQLException e) {
+                LOGGER.error(e);
+                attributes = new HashMap<String, List<DbAttribute>>();
+            }
+        }
+        return attributes;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/50174deb/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbTableLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbTableLoader.java b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbTableLoader.java
new file mode 100644
index 0000000..da9821c
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/loader/DbTableLoader.java
@@ -0,0 +1,189 @@
+/*****************************************************************
+ *   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
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.access.loader;
+
+import org.apache.cayenne.access.DbLoaderDelegate;
+import org.apache.cayenne.access.loader.filters.*;
+import org.apache.cayenne.map.*;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.*;
+
+/**
+ * @since 4.0
+ */
+public class DbTableLoader {
+
+    private static final Log LOGGER = LogFactory.getLog(DbTableLoader.class);
+
+    private static final String WILDCARD = "%";
+
+    private final String catalog;
+    private final String schema;
+
+    private final DatabaseMetaData metaData;
+    private final DbLoaderDelegate delegate;
+
+    private final DbAttributesLoader attributesLoader;
+
+    public DbTableLoader(String catalog, String schema, DatabaseMetaData metaData, DbLoaderDelegate delegate, DbAttributesLoader attributesLoader) {
+        this.catalog = catalog;
+        this.schema = schema;
+        this.metaData = metaData;
+        this.delegate = delegate;
+
+        this.attributesLoader = attributesLoader;
+    }
+
+
+    /**
+     * Returns all tables for given combination of the criteria. Tables returned
+     * as DbEntities without any attributes or relationships.
+     *
+     * @param types  The types of table names to retrieve, null returns all types.
+     * @return
+     * @since 4.0
+     */
+    public List<DetectedDbEntity> getDbEntities(TableFilter filters, String[] types) throws SQLException {
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("Read tables: catalog=" + catalog + ", schema=" + schema + ", types="
+                    + Arrays.toString(types));
+        }
+
+        ResultSet rs = metaData.getTables(catalog, schema, WILDCARD, types);
+
+        List<DetectedDbEntity> tables = new LinkedList<DetectedDbEntity>();
+        try {
+            while (rs.next()) {
+                // Oracle 9i and newer has a nifty recycle bin feature... but we don't
+                // want dropped tables to be included here; in fact they may even result
+                // in errors on reverse engineering as their names have special chars like
+                // "/", etc. So skip them all together
+
+                String name = rs.getString("TABLE_NAME");
+                if (name == null) {
+                    continue;
+                }
+
+                DetectedDbEntity table = new DetectedDbEntity(name);
+
+                String catalog = rs.getString("TABLE_CAT");
+                table.setCatalog(catalog);
+
+                String schema = rs.getString("TABLE_SCHEM");
+                table.setSchema(schema);
+                if (!(this.catalog == null || this.catalog.equals(catalog)) ||
+                        !(this.schema == null || this.schema.equals(schema))) {
+
+                    LOGGER.error(catalog + "." + schema + "." + name + " wrongly loaded for catalog/schema : "
+                            + this.catalog + "." + this.schema);
+
+                    continue;
+                }
+
+                PatternFilter includeTable = filters.isIncludeTable(table.getName());
+                if (includeTable != null) {
+                    tables.add(table);
+                }
+            }
+        } finally {
+            rs.close();
+        }
+        return tables;
+    }
+
+    /**
+     * Loads dbEntities for the specified tables.
+     * @param config
+     * @param types
+     */
+    public List<DbEntity> loadDbEntities(DataMap map, DbLoaderConfiguration config, String[] types) throws SQLException {
+        /** List of db entities to process. */
+
+        List<DetectedDbEntity> tables
+                = getDbEntities(config.getFiltersConfig().tableFilter(catalog, schema), types);
+
+        List<DbEntity> dbEntities = new ArrayList<DbEntity>();
+        for (DbEntity dbEntity : tables) {
+            DbEntity oldEnt = map.getDbEntity(dbEntity.getName());
+            if (oldEnt != null) {
+                Collection<ObjEntity> oldObjEnt = map.getMappedEntities(oldEnt);
+                if (!oldObjEnt.isEmpty()) {
+                    for (ObjEntity objEntity : oldObjEnt) {
+                        LOGGER.debug("Delete ObjEntity: " + objEntity.getName());
+                        map.removeObjEntity(objEntity.getName(), true);
+                        delegate.objEntityRemoved(objEntity);
+                    }
+                }
+
+                LOGGER.debug("Overwrite DbEntity: " + oldEnt.getName());
+                map.removeDbEntity(oldEnt.getName(), true);
+                delegate.dbEntityRemoved(oldEnt);
+            }
+
+            map.addDbEntity(dbEntity);
+
+            delegate.dbEntityAdded(dbEntity);
+
+            // delegate might have thrown this entity out... so check if it is still
+            // around before continuing processing
+            if (map.getDbEntity(dbEntity.getName()) == dbEntity) {
+                dbEntities.add(dbEntity);
+                attributesLoader.loadDbAttributes(dbEntity);
+                if (!config.isSkipPrimaryKeyLoading()) {
+                    loadPrimaryKey(dbEntity);
+                }
+            }
+        }
+
+        return dbEntities;
+    }
+
+    private void loadPrimaryKey(DbEntity dbEntity) throws SQLException {
+        ResultSet rs = metaData.getPrimaryKeys(dbEntity.getCatalog(), dbEntity.getSchema(), dbEntity.getName());
+        try {
+            while (rs.next()) {
+                String columnName = rs.getString("COLUMN_NAME");
+                DbAttribute attribute = dbEntity.getAttribute(columnName);
+
+                if (attribute != null) {
+                    attribute.setPrimaryKey(true);
+                } else {
+                    // why an attribute might be null is not quiet clear
+                    // but there is a bug report 731406 indicating that it is possible
+                    // so just print the warning, and ignore
+                    LOGGER.warn("Can't locate attribute for primary key: " + columnName);
+                }
+
+                String pkName = rs.getString("PK_NAME");
+                if (pkName != null && dbEntity instanceof DetectedDbEntity) {
+                    ((DetectedDbEntity) dbEntity).setPrimaryKeyName(pkName);
+                }
+
+            }
+        } finally {
+            rs.close();
+        }
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/cayenne/blob/50174deb/cayenne-server/src/test/java/org/apache/cayenne/access/DbLoaderIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DbLoaderIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DbLoaderIT.java
index e002db5..18c5d99 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/DbLoaderIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DbLoaderIT.java
@@ -19,12 +19,6 @@
 
 package org.apache.cayenne.access;
 
-import java.sql.Types;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 import org.apache.cayenne.access.loader.DbLoaderConfiguration;
 import org.apache.cayenne.access.loader.filters.FiltersConfig;
 import org.apache.cayenne.access.loader.filters.PatternFilter;
@@ -33,27 +27,21 @@ import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.di.Inject;
-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.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.*;
 import org.apache.cayenne.unit.UnitDbAdapter;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
 import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.apache.commons.lang3.tuple.Pair;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-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;
+import java.sql.Types;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.Assert.*;
 
 @UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
 public class DbLoaderIT extends ServerCase {
@@ -106,15 +94,15 @@ public class DbLoaderIT extends ServerCase {
 
         String tableLabel = adapter.tableTypeForTable();
 
-        Collection<Pair<DbEntity, PatternFilter>> tables = loader.getTables(new DbLoaderConfiguration(), new String[] { tableLabel })
-                .values().iterator().next().values();
+        List<DetectedDbEntity> tables = loader.createTableLoader(null, null, TableFilter.everything())
+                .getDbEntities(TableFilter.everything(), new String[]{tableLabel});
 
         assertNotNull(tables);
 
         boolean foundArtist = false;
 
-        for (Pair<DbEntity, PatternFilter> table : tables) {
-            if ("ARTIST".equalsIgnoreCase(table.getKey().getName())) {
+        for (DetectedDbEntity table : tables) {
+            if ("ARTIST".equalsIgnoreCase(table.getName())) {
                 foundArtist = true;
                 break;
             }
@@ -129,9 +117,9 @@ public class DbLoaderIT extends ServerCase {
         DbLoaderConfiguration config = new DbLoaderConfiguration();
         config.setFiltersConfig(
                 FiltersConfig.create("WRONG", null, TableFilter.everything(), PatternFilter.INCLUDE_NOTHING));
-        Map<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>> tables = loader.getTables(
-                config,
-                new String[]{adapter.tableTypeForTable()});
+        List<DetectedDbEntity> tables = loader
+                .createTableLoader("WRONG", null, TableFilter.everything())
+                    .getDbEntities(TableFilter.everything(), new String[]{adapter.tableTypeForTable()});
 
         assertNotNull(tables);
         assertTrue(tables.isEmpty());
@@ -143,9 +131,9 @@ public class DbLoaderIT extends ServerCase {
         DbLoaderConfiguration config = new DbLoaderConfiguration();
         config.setFiltersConfig(
                 FiltersConfig.create(null, "WRONG", TableFilter.everything(), PatternFilter.INCLUDE_NOTHING));
-        Map<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>> tables = loader.getTables(
-                config,
-                new String[]{adapter.tableTypeForTable()});
+        List<DetectedDbEntity> tables = loader
+                .createTableLoader(null, "WRONG", TableFilter.everything())
+                .getDbEntities(TableFilter.everything(), new String[]{adapter.tableTypeForTable()});
 
         assertNotNull(tables);
         assertTrue(tables.isEmpty());
@@ -159,12 +147,10 @@ public class DbLoaderIT extends ServerCase {
 
         loader.setCreatingMeaningfulPK(true);
 
-        Map<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>> testLoader = loader.getTables(CONFIG, tableLabel);
-        if (testLoader.isEmpty()) {
-            testLoader = loader.getTables(CONFIG, tableLabel);
-        }
+        List<DbEntity> entities = loader
+                .createTableLoader(null, null, TableFilter.everything())
+                .loadDbEntities(map, CONFIG, tableLabel);
 
-        List<DbEntity> entities = loader.loadDbEntities(map, CONFIG, testLoader);
         loader.loadObjEntities(map, CONFIG, entities);
 
         ObjEntity artist = map.getObjEntity("Artist");
@@ -193,7 +179,10 @@ public class DbLoaderIT extends ServerCase {
         String tableLabel = adapter.tableTypeForTable();
 
         // *** TESTING THIS ***
-        List<DbEntity> entities = loader.loadDbEntities(map, CONFIG, loader.getTables(CONFIG, new String[]{tableLabel}));
+        List<DbEntity> entities = loader
+                .createTableLoader(null, null, TableFilter.everything())
+                .loadDbEntities(map, CONFIG, new String[]{adapter.tableTypeForTable()});
+
 
         assertDbEntities(map);
 
@@ -202,15 +191,7 @@ public class DbLoaderIT extends ServerCase {
         }
 
         // *** TESTING THIS ***
-        Map<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>> tables =
-                new HashMap<Pair<String, String>, Map<String, Pair<DbEntity, PatternFilter>>>();
-
-        Map<String, Pair<DbEntity, PatternFilter>> value = new HashMap<String, Pair<DbEntity, PatternFilter>>();
-        for (DbEntity e : entities) {
-            value.put(e.getName(), Pair.of(e, PatternFilter.INCLUDE_EVERYTHING));
-        }
-        tables.put(Pair.of((String) null, (String) null), value);
-        loader.loadDbRelationships(CONFIG, tables);
+        loader.loadDbRelationships(CONFIG, null, null, entities);
 
         if (supportsFK) {
             Collection<DbRelationship> rels = getDbEntity(map, "ARTIST").getRelationships();


Mime
View raw message