C# 为什么我使用ODP.NET OracleDataAdapter而不是System.Data.OracleClient';调用DbDataAdapter.Update时是否调用了s适配器?

C# 为什么我使用ODP.NET OracleDataAdapter而不是System.Data.OracleClient';调用DbDataAdapter.Update时是否调用了s适配器?,c#,.net,oracle,ado.net,odp.net,C#,.net,Oracle,Ado.net,Odp.net,我做了以下工作: protected int CreateComponent(DbConnection cnctn, string tableName) { int newId; DbCommand selectCmd = _provFactory.CreateCommand(); selectCmd.Connection = cnctn; selectCmd.CommandText = string.Format( "SELECT *

我做了以下工作:

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的人来说可能听起来很荒谬。无论如何,我只插入一行。我还没有尝试过手工构建Insert命令,稍后我会这么做。命令生成器应该处理没有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时插入(与上面的代码类似)。当我命令自己构建时,我为FLOAT(126)列提供DbParameter.DbType=DbType.Double。如果我自己构建,所有正常的双精度值都可以接受
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家供应商工作


谢谢并致以最诚挚的问候-Matti

您在填写表格后是否尝试添加PK

_dataSet.Tables[tableName].PrimaryKey = (new List<DataColumn>() { _dataSet.Tables[0].Columns["ID"] }).ToArray();
\u dataSet.Tables[tableName].PrimaryKey=(新列表(){u dataSet.Tables[0]。列[“ID”})。ToArray();

首先,我认为您应该将此作为错误报告给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]);
    }

根据我的经验,ODP.NET有一些奇怪的行为,有时会出现奇怪的bug,具体取决于您使用的版本和Oracle客户端等。遗憾的是,
System.Data.OracleClient
目前已不推荐使用。。。这些东西让我使用了一个商业供应商。。。相当高兴,到目前为止有一个bug(该bug已立即得到纠正)并且从未回头。。。。我不知道这是否是您的一个选项,但是…显示此行为的表是否有主键?是的,它有它的“ID”。我进一步测试了它,并像上面那样获取了maxid行,但随后将新行的值从第一个FLOAT(126)列更改为最后一列(NUMBERs和FLOAT(126)s得到0,VARCHAR2s得到短无意义字符串,DATEs得到DateTime.Now),没有问题!当我离开第一个float字段时,会引发异常,因此它不允许从db获取值!!!我刚刚注意到
FLOAT(126)
-这确实很奇怪,尤其是在Oracle数据库中。。。你能详细说明一下吗?试着改用
NUMBER
吗?对于Oracld DB来说,它更“自然”,精度略高(38而不是37.9)。什么是CurrentDataSet.Tables[0]?但如果你想把ID列添加为PK,我没有。我尝试了一下。添加“ID”作为PK没有效果:(对不起,这本来是数据集。我已经更新了我的答案,尽管看起来你已经计算了这么多并尝试了。谢谢GTG!我自己也找到了一个解决方法,我编辑了这个问题(构建我自己)。如果可行,您的解决方案就足够了!代码中已经充满了检查提供程序的条件,因为参数和架构等的处理方式不同。我今天将尝试测试它,并肯定会接受它是否可行。再次感谢!再次感谢!它可以正常工作,这很奇怪,因为数据适配器和构建器都是OracleDataAd的实例apter和OracleCommandBuilder。有什么解释吗?在接受之前,我会进行更多的测试。我做了更多的测试,发现问题似乎出在commandbuilder.GetInsertCommand()中。我的测试是对所有对象使用_provFactory.Create…,并使用System.Data数据类型。如果这样做,则效果很好:dataAdapter.InsertCommand=((Oracle.DataAccess.Client.OracleCommandBuilder)cmdBuilder)。GetInsertCommand();这似乎很奇怪-人们会认为这是一个虚拟函数,所以这个类型转换应该没有效果。真的很奇怪。无论如何,问题“解决了”。很奇怪,这个常见操作中的错误没有被注意到(根据我在web上的搜索)。可能没有人真正使用ODP.NET,因为它充满了错误。