DbUnit: NoSuchColumnException и чувствительность к регистру

До публикации этого я немного искал Google, я искал в dbunit-user архивы и немного также в списке ошибок DbUnit, но я не нашел, что находясь в поиске. К сожалению, ответы здесь тоже не помогли мне.

Я использую DbUnit 2.4.8 с MySQL 5.1.x для заполнения в setUp некоторых таблиц JForum. Сначала проблема возникает в таблице jforum_users, созданной этим script

CREATE TABLE `jforum_users` (
       `user_id` INT(11) NOT NULL AUTO_INCREMENT,
       `user_active` TINYINT(1) NULL DEFAULT NULL,
       `username` VARCHAR(50) NOT NULL DEFAULT '',
       `user_password` VARCHAR(32) NOT NULL DEFAULT '',
       [...]
       PRIMARY KEY (`user_id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=14

Выполнение REFRESH в качестве операции настройки базы данных вызывает следующее исключение.

org.dbunit.dataset.NoSuchColumnException: jforum_users.USER_ID -
(Non-uppercase input column: USER_ID) in ColumnNameToIndexes cache
map. Note that the map column names are NOT case sensitive.
       at org.dbunit.dataset.AbstractTableMetaData.getColumnIndex(AbstractTableMetaData.java:117)
       at org.dbunit.operation.AbstractOperation.getOperationMetaData(AbstractOperation.java:89)
       at org.dbunit.operation.RefreshOperation.execute(RefreshOperation.java:98)
       at org.dbunit.AbstractDatabaseTester.executeOperation(AbstractDatabaseTester.java:190)
       at org.dbunit.AbstractDatabaseTester.onSetup(AbstractDatabaseTester.java:103)
       at net.jforum.dao.generic.AbstractDaoTest.setUpDatabase(AbstractDaoTest.java:43)

Я посмотрел в AbstractTableMetaData.java источники, и ничего не кажется -статически ошибочным. Метод

private Map createColumnIndexesMap(Column[] columns)

использует

columns[i].getColumnName().toUpperCase()

при написании клавиш карты. И тогда метод

public int getColumnIndex(String columnName)

использует

String columnNameUpperCase = columnName.toUpperCase();
Integer colIndex = (Integer) this._columnsToIndexes.get(columnNameUpperCase);

для чтения объекта с карты.

Я действительно не могу раскрыть, что происходит... Кто-нибудь может мне помочь?

Изменить после последнего ответа @limc

Я использую PropertiesBasedJdbcDatabaseTester для настройки моего DbUnit env, как показано ниже:

Properties dbProperties = new Properties();
dbProperties.load(new FileInputStream(testConfDir+"/db.properties"));
System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS, 
    dbProperties.getProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_DRIVER_CLASS));
System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL, 
    dbProperties.getProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_CONNECTION_URL));
System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME, 
    dbProperties.getProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_USERNAME));
System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD, 
    dbProperties.getProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_PASSWORD));
System.setProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_SCHEMA, 
    dbProperties.getProperty(PropertiesBasedJdbcDatabaseTester.DBUNIT_SCHEMA));

databaseTester = new PropertiesBasedJdbcDatabaseTester();
databaseTester.setSetUpOperation(getSetUpOperation());
databaseTester.setTearDownOperation(getTearDownOperation());

IDataSet dataSet = getDataSet();
databaseTester.setDataSet(dataSet);

databaseTester.onSetup();

Ответ 1

У меня есть причина полагать, что проблема связана с столбцом user_id как идентификатором записи. У меня аналогичная проблема в прошлом, когда идентификатор строки генерируется изначально SQL Server. Сейчас я не на своем рабочем столе, но попробую это решение, чтобы узнать, помогает ли это: http://old.nabble.com/case-sensitivity-on-tearDown--td22964025.html

ОБНОВЛЕНИЕ - 02-03-11

У меня есть рабочее решение здесь. Здесь мой тестовый код: -

MySQL Script

CREATE TABLE `jforum_users` (
       `user_id` INT(11) NOT NULL AUTO_INCREMENT,
       `user_active` TINYINT(1) NULL DEFAULT NULL,
       `username` VARCHAR(50) NOT NULL DEFAULT '',
       PRIMARY KEY (`user_id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=14

dbunit-test.xml Тестовый файл

<?xml version='1.0' encoding='UTF-8'?>

<dataset>
    <jforum_users user_id="100" username="First User" />
</dataset>

Код Java

Class.forName("com.mysql.jdbc.Driver");
Connection jdbcConnection = DriverManager.getConnection("jdbc:mysql://localhost:8889/test", "", "");
IDatabaseConnection con = new DatabaseConnection(jdbcConnection);

InputStream is = getClass().getClassLoader().getResourceAsStream("dbunit-test.xml");
IDataSet dataSet = new FlatXmlDataSetBuilder().build(is);
DatabaseOperation.CLEAN_INSERT.execute(con, dataSet);

con.close();

У меня не было никаких ошибок, и строка была добавлена ​​в базу данных.

Просто FYI, я попробовал REFRESH и отлично работает без ошибок: -

DatabaseOperation.REFRESH.execute(con, dataSet);

Я использую DBUnit 2.4.8 и MySQL 5.1.44.

Надеюсь, что это поможет.

Ответ 2

Сегодня у меня была аналогичная проблема (с использованием интерфейса IDatabaseTester, добавленного в v2.2 против MySQL), и провел несколько часов, разрывая мои волосы. OP использует приложение PropertiesBasedJdbcDatabaseTester, в то время как я использовал его "родительский" JdbcDatabaseTester.

DBUnit имеет ответ на часто задаваемый вопрос, связанный с этим исключением NoSuchColumnException (специфичный для MySQL), но он выглядит как недосмотр для меня, что он пренебрегает упоминанием о том, что каждое соединение, полученное из интерфейса getConnection(), будет иметь отдельную конфигурацию. На самом деле я бы зашел так далеко, чтобы называть его ошибкой, учитывая формулировку различных бит doco, на которые я смотрел сегодня, и имена соответствующих классов (например, DatabaseConfig, но за соединение?).

Во всяком случае, в разделах кода, таких как setup/teardown (пример ниже), вы даже не предоставляете объект Connection, поэтому я не мог видеть, как установить там конфигурацию.

dbTester.setDataSet(beforeData);
dbTester.onSetup();

В итоге я просто расширил JdbcDatabaseTester до @Override метода getConnection() и каждый раз вводил конфигурацию, специфичную для MySQL:

class MySQLJdbcDatabaseTester extends org.dbunit.JdbcDatabaseTester {
  public MySQLJdbcDatabaseTester(String driverClass, String connectionUrl, String username, String password,
                                 String schema) throws ClassNotFoundException {
    super(driverClass, connectionUrl, username, password, schema);
  }

  @Override
  public IDatabaseConnection getConnection() throws Exception {
    IDatabaseConnection connection = super.getConnection();
    DatabaseConfig dbConfig = connection.getConfig();
    dbConfig.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory());
    dbConfig.setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MySqlMetadataHandler());
    return connection;
  }
}

И, наконец, все ошибки исчезли.

Ответ 3

Когда я получил эту ошибку, это произошло из-за того, что моя схема не имела нулевого ограничения для столбца, но этот столбец отсутствовал в моем файле данных.

Например, моя таблица имела

<table name="mytable">
    <column>id</column>
    <column>entity_type</column>
    <column>deleted</column>
</table>

<dataset>
    <mytable id="100" entity_type"2"/>
</dataset>

У меня есть ненулевое ограничение на удаленный столбец, и когда я запускаю тест, я получаю исключение NoSuchColumnException.

Когда я меняю набор данных на

<mytable id="100" entity_type"2" deleted="0"/>

Я прохожу мимо Exception.

Ответ 4

Я пришел сюда, чтобы найти ответ на эту проблему. Для меня проблема была в стратегии именования Hibernate. Я понял, что это проблема, поскольку show_sql был истинным в Spring application.properties:

spring.jpa.show-sql=true

Я мог видеть сгенерированную таблицу SQL и имя поля было "FACT_NUMBER" вместо "factNumber", которое у меня было в моем dbunit xml.

Это было решено, вызывая стратегию именования по умолчанию (по иронии судьбы, по умолчанию это значение org.hibernate.cfg.ImprovedNamingStrategy, которое помещается в '_'):

spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultNamingStrategy

Ответ 5

Я столкнулся с этой проблемой, и причина в том, что в dtd моего файла набора данных было описание, отличное от таблицы, где я хотел вставить данные.

Итак, проверьте, что ваша таблица, в которую вы хотите вставить данные, имеет те же столбцы, что и ваш файл dtd.

когда я удаляю в файле dtd столбец, который не был в таблице, где я вставил данные, проблема исчезла.

Ответ 6

В моем случае это был файл csv, закодированный в UTF-8 с BOM char в начале. Я использовал блокнот для создания файлов csv. Используйте notepade ++, чтобы избежать сохранения спецификации char.

Ответ 7

У меня была одна и та же проблема, затем я понял, что я использовал другое имя столбца в моей базе данных, чем то, что у меня есть в моем XML файле.

Я уверен, что у вас проблемы с user_id vs USER_ID.

Ответ 8

Хорошо, я столкнулся с такой же проблемой, и нашел решение. Способ создания тестовых данных неверен, для какого набора данных мы использовали. Мы использовали набор данных xml, для которого правильный формат вы используете FlatXmlDataSet, тогда есть другой формат, для более подробного объяснения читайте в приведенной ниже ссылке. xml должен быть в следующем формате.

<?xml version="1.0" encoding="UTF-8"?>
<dataset>
    <table>
        <column>id</column>
        <column>name</column>
        <column>department</column>
        <column>startDate</column>
        <column>endDate</column>
        <row>
            <value>999</value>
            <value>TEMP</value>
            <value>TEMP DEPT</value>
            <value>2113-10-13</value>
            <value>2123-10-13</value>
        </row>
    </table>
</dataset>

Если вы хотите узнать больше, перейдите по этой ссылке: http://dbunit.sourceforge.net/components.html