почему я получаю OracleTruncateException с ODP.NET OracleDataAdapter, но не с адаптером System.Data.OracleClient, когда вызывается DbDataAdapter.Update? - PullRequest
5 голосов
/ 11 ноября 2011

Я делаю следующее:

protected int CreateComponent(DbConnection cnctn, string tableName)
{
    int newId;

    DbCommand selectCmd = _provFactory.CreateCommand();
    selectCmd.Connection = cnctn;
    selectCmd.CommandText = string.Format(
            "SELECT * FROM {0} WHERE ID = (SELECT MAX(ID) FROM {0})", tableName);

    DbDataAdapter dataAdapter = _provFactory.CreateDataAdapter();
    dataAdapter.SelectCommand = selectCmd;

      ...
    // create Insert/Update/Delete commands with a builder for the data adapter
      ...

    dataAdapter.Fill(_dataSet, tableName);      

    newId = Convert.ToInt32(_dataSet.Tables[tableName].Rows[0]["id"]) + 1000000;

    DataRow newRow = _dataSet.Tables[tableName].NewRow();
    newRow.ItemArray = _dataSet.Tables[tableName].Rows[0].ItemArray;
    newRow["ID"] = newId;

    _dataSet.Tables[tableName].Rows.Add(newRow); 
}

Это прекрасно работает для OleDb и System.Data.OracleClient. Однако с провайдером Oracle.DataAccess.Client я получаю:

Oracle.DataAccess.Types.OracleTruncateException (16550) 

с усеченным текстом, полученным из:

at System.Data.Common.DbDataAdapter.UpdatedRowStatusErrors  
at System.Data.Common.DbDataAdapter.UpdatedRowStatus  
at System.Data.Common.DbDataAdapter.Update
at Oracle.DataAccess.Client.OracleDataAdapter.Update  
at System.Data.Common.DbDataAdapter.UpdateFromDataTable  
at System.Data.Common.DbDataAdapter.Update

Таблицы, которые я получаю, это большие таблицы, в других есть 61 поле. Типы всех полей ограничены:

VARCHAR2(different lenghts)
VARCHAR2(different lenghts) NOT NULL
FLOAT(126) NOT NULL     
NUMBER NOT NULL
DATE

Изменить, чтобы предотвратить слишком много комментариев:

-Я не могу изменить тип данных или что-либо еще в базе данных.

-В DataRow эти столбцы FLOAT (126) имеют тип данных System.Decimal (как при использовании других провайдеров)

-В отличие от того, что я говорил ранее: ID не является первичным ключом. Это уникальный индекс. Таблица не имеет первичного ключа (как определение Oracle) Я должен признать, что я думал, что уникальный индекс является первичным ключом, который может показаться нелепым для людей, знакомых с Oracle. В любом случае я делаю только Вставку 1 ряда. Я не пытался собрать команду вставки, которую я сделаю чуть позже. Построители команд должны обрабатывать таблицы без PK (http://msdn.microsoft.com/en-us/library/tf579hcz.aspx: «Команда SelectCommand также должна возвращать хотя бы один первичный ключ или уникальный столбец.»)

-Это также работает с ODP.NET/Oracle.DataAccess.Client, если:

  • Я даю всем значениям FLOAT (126) -колонок 0 до последнего метода строка. Даже если присвоить значение 1 или 2 любому, возникает то же исключение, когда DbDataAdapter.Update называется.

или

  • Я сам создаю DbDataAdapter.Insertommand и там только вставить (как код выше), когда вызывается DbDataAdapter.Update. Когда я создаю сам, я даю DbParameter.DbType = DbType.Double для FLOAT (126) -колонок. Если я создаю его сам, все нормальные двойные значения принимаются.

app.config:

<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup>
  <system.data>
  <DbProviderFactories>
    <add name="Oracle Data Provider for .NET"
            invariant="Oracle.DataAccess.Client"
            description="Oracle Data Provider for .NET"
            type="Oracle.DataAccess.Client.OracleClientFactory,
                  Oracle.DataAccess,
                  Version=2.112.1.0,
                  Culture=neutral,
                  PublicKeyToken=89b483f429c47342" />
  </DbProviderFactories>
  </system.data>

есть идеи, в чем причина и как я заставлю это работать для всех 3 провайдеров?

Спасибо и наилучшими пожеланиями - Матти

Ответы [ 2 ]

1 голос
/ 18 ноября 2011

Во-первых, я думаю, вы должны сообщить об этом в Oracle как об ошибке.Ошибка происходит, даже если таблица действительно мала.Это не имеет ничего общего с индексами или первичными ключами, ошибка возникает, даже если таблица не имеет индекса.Если вы установите значение ID равным 0, вставка будет работать нормально.

Мне удалось создать обходной путь, хотя он не является хорошим, но может оказаться достаточно для вашего случая.

Обходной путь - использовать собственные клиентские классы Oracle для ODP.Net, поэтому вам нужно будет проверить, настроено ли ваше приложение для ODP или одного из них, и выбрать соответствующий код соответствующим образом.

A "ODPТолько "версия вашей функции может выглядеть так:

    protected void CreateComponentODPOnly(Oracle.DataAccess.Client.OracleConnection cntn, string tableName)
    {
        int newId;

        System.Data.DataSet _dataSet = new DataSet();

        Oracle.DataAccess.Client.OracleCommand selectCmd = new Oracle.DataAccess.Client.OracleCommand();
        selectCmd.Connection = cntn;
        selectCmd.CommandText = string.Format(
                "SELECT * FROM {0} WHERE ID = (SELECT MAX(ID) FROM {0})", tableName);

        Oracle.DataAccess.Client.OracleDataAdapter dataAdapter = new Oracle.DataAccess.Client.OracleDataAdapter();
        Oracle.DataAccess.Client.OracleCommandBuilder cmdBuilder = new Oracle.DataAccess.Client.OracleCommandBuilder();
        dataAdapter.SelectCommand = selectCmd;
        cmdBuilder.DataAdapter = dataAdapter;

        dataAdapter.Fill(_dataSet, tableName);

        newId = Convert.ToInt32(_dataSet.Tables[tableName].Rows[0]["id"]) + 1000000;

        DataRow newRow = _dataSet.Tables[tableName].NewRow();
        newRow.ItemArray = _dataSet.Tables[tableName].Rows[0].ItemArray;
        newRow["ID"] = (Decimal)newId;

        _dataSet.Tables[tableName].Rows.Add(newRow);
        dataAdapter.InsertCommand = cmdBuilder.GetInsertCommand();
        dataAdapter.Update(_dataSet.Tables[tableName]);
    }
0 голосов
/ 15 ноября 2011

Вы пытались добавить PK после заполнения таблицы?

_dataSet.Tables[tableName].PrimaryKey = (new List<DataColumn>() { _dataSet.Tables[0].Columns["ID"] }).ToArray();
...