将 DbUnit 与没有主键的表一起使用

Posted

技术标签:

【中文标题】将 DbUnit 与没有主键的表一起使用【英文标题】:Using DbUnit with tables which do not have primary keys 【发布时间】:2012-02-26 05:04:36 【问题描述】:

我正在尝试设置我的单元测试环境以使用 DbUnit。

我遇到了一些问题,因为我试图控制的表没有主键。我收到了org.dbunit.dataset.NoPrimaryKeyException

我已按照http://dbunit.wikidot.com/noprimarykeytable 此处的步骤操作,但我该如何使用:

connection.getConfig().setProperty("http://www.dbunit.org/properties/primaryKeyFilter", new MyPrimaryKeyFilter("A1"));

我的每张桌子?

例如,我有以下数据库:

CREATE TABLE `NO_PK1` (
  `A1` int(11) NOT NULL,
  `A2` varchar(50) default NULL
);

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
  <NO_PK1 A1="1" A2="Test1" />
  <NO_PK1 A1="2" A2="Test2" />
  <NO_PK1 A1="3" />
</dataset>

CREATE TABLE `NO_PK2` (
  `B1` int(11) NOT NULL,
  `B2` varchar(50) default NULL
);

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
  <NO_PK2 B1="1" B2="Test1" />
  <NO_PK2 B1="2" B2="Test2" />
  <NO_PK2 B1="3" />
</dataset>

CREATE TABLE `NO_PK3` (
  `C1` int(11) NOT NULL,
  `C2` varchar(50) default NULL
);

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
  <NO_PK3 C1="1" C2="Test1" />
  <NO_PK3 C1="2" C2="Test2" />
  <NO_PK3 C1="3" />
</dataset>

在这种情况下如何重写connection.getConfig().setProperty("http://www.dbunit.org/properties/primaryKeyFilter", new MyPrimaryKeyFilter("A1"));

非常感谢您的建议。

【问题讨论】:

【参考方案1】:

您需要确保您的 MyPrimaryKeyFilter 处理架构中的所有表。在示例中,只有一个表,因此提供的简单过滤器类可以正常工作。在您的情况下,我可能会更改该类以获取包含表的 Map -> pk 列名映射:

class MyPrimaryKeyFilter implements IColumnFilter 
        private Map<String, String> pseudoKey = null;

        MyPrimaryKeyFilter(Map<String, String> pseudoKey) 
            this.pseudoKey = pseudoKey;
        

        public boolean accept(String tableName, Column column) 
            return column.getColumnName().equalsIgnoreCase(pseudoKey.get(tableName));
        

    

然后使用 NO_PK1 -> A1、NO_PK2 -> B1 和 NO_PK3 -> C1 条目设置地图。

【讨论】:

谢谢 slushi。这就说得通了。如果其中一张表有一个由多个字段组成的键怎么办? 我认为您可以将 Map 更改为 Map> 并进行包含检查。 所以return语句变成return pseudoKey.get(tableName).contains(column.getColumnName());? 我认为是这样,您可能需要稍微更改它以处理不区分大小写的问题。我会进行测试以查看 column.getColumnName() 返回的情况。或者您可以将 Set 中的所有内容以及 column.getColumnName() 中的值大写。【参考方案2】:

我遇到了同样的问题并在这些博客中找到了解决方案:

http://www.expertaya.com/2011/04/20/dbunit-composite-primary-keys/ http://blog.eflow.org/archives/65 http://www.baselogic.com/blog/development/test-driven-development/dbunit-unable-import-data-collectiontable-witout-primary-key/

所有博客作者均以http://dbunit.wikidot.com/noprimarykeytable开头

这段代码展示了检查 id 的不同策略:

public static IDatabaseConnection getConnection(DataSource ds) throws Exception 
    Connection con = ds.getConnection();
    final DatabaseMetaData dbMetaData = con.getMetaData();
    DatabaseConnection dbUnitCon = new DatabaseConnection(con, dbMetaData.getUserName().toUpperCase());
    DatabaseConfig dbUnitConfig = dbUnitCon.getConfig();
    dbUnitConfig.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new Oracle10DataTypeFactory());
    dbUnitConfig.setProperty(DatabaseConfig.FEATURE_SKIP_ORACLE_RECYCLEBIN_TABLES, Boolean.TRUE);
    dbUnitConfig.setProperty(DatabaseConfig.PROPERTY_PRIMARY_KEY_FILTER, new IColumnFilter() 

        Map<String, List<String>> tablePrimaryKeyMap = new HashMap<>();
        
            tablePrimaryKeyMap.put("CLIENT", Arrays.asList(new String[]"FIRST_NAME", "MIDDLE_NAME", "LAST_NAME"));
            // ...
        

        @Override
        public boolean accept(String tableName, Column column) 
            if ((tableName.startsWith("DATA_") || tableName.startsWith("PAYMENT_"))
                    && ("COMPANY".equalsIgnoreCase(tableName) || "FILIAL".equalsIgnoreCase(tableName)
                        || "BRANCH".equalsIgnoreCase(tableName) || "CASTOMER".equalsIgnoreCase(tableName)
                        || "XDATE".equalsIgnoreCase(tableName)))
                return true;
            if (tablePrimaryKeyMap.containsKey(tableName))
                return tablePrimaryKeyMap.get(tableName).contains(column.getColumnName());
            else if ("id".equalsIgnoreCase(column.getColumnName())) 
                return true;
            
            try 
                ResultSet rs = dbMetaData.getPrimaryKeys(null, null, tableName);
                while (rs.next()) 
                    rs.getString("COLUMN_NAME");
                    if (rs.getString("COLUMN_NAME").equalsIgnoreCase(column.getColumnName())) 
                        return true;
                    
                
             catch (SQLException ex) 
                Logger.getLogger(DistributionControllerDbTest.class.getName()).log(Level.SEVERE, null, ex);
            
            return false;
        
    );
    return dbUnitCon;

【讨论】:

以上是关于将 DbUnit 与没有主键的表一起使用的主要内容,如果未能解决你的问题,请参考以下文章

为啥没有主键的表是个坏主意?

Oracle对没有主键的表分页

维度建模:如何创建没有代理主键的表?

脚本找出mysql中缺少主键的表

sql 查询没有主键的表

火花 jdbc 读取调整 where 没有主键的表