当DbDataAdapter.Update调用时,为什么我使用ODP.NET OracleDataAdapter获取OracleTruncateException而不使用System.Data.OracleClient的适配器?

我做了以下事情:

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)-columns值0。 即使在调用DbDataAdapter.Update时给任何引发相同的exception值1或2。

要么

  • 我自己创建了DbDataAdapter.Insertommand,并且在调用DbDataAdapter.Update时只有插入(如上面的代码)。 当我自己构建cmd时,我为FLOAT(126)-columns提供DbParameter.DbType = DbType.Double。 如果我自己构建它,则接受所有正常的双值。

的app.config:

       

任何想法是什么原因以及我将如何让它适用于所有3个提供商?

谢谢和最诚挚的问候 – 马蒂

首先,我认为您应该将此报告给Oracle作为错误。 即使表格非常小​​,也会发生错误。 它与索引或主键无关,即使表没有索引也会发生错误。 如果将ID的值设置为0,则插入将运行正常。

我设法创建了一个解决方法,虽然它不是一个好的,它可能足够你的情况。

解决方法是使用ODP.Net的本机Oracle客户端类,因此您必须检查您的应用程序是否已针对ODP或其他任何一个配置,并相应地选择您的代码。

您的函数的“仅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]); } 

填写表格后,您是否尝试过添加PK?

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