首页 > 解决方案 > 将 C# 对象列表中的多行数据插入 Oracle 12 数据库中的表中

问题描述

我想通过从 C#.NET 调用它的存储过程插入多行。我正在使用 Oracle 为 .NET 提供的 OracleDataAccess.dll 非托管 .net 驱动程序并使用 VS 2015。我的程序是一个控制台程序,它将读取 excel 文件(一个接一个)查看 excel 中的特定工作表并插入来自在 oracle 中将工作表放入表中。

我研究过,发现有人说可以通过 XML、UDT 和 OracleBulkCopy 完成,但我发现的代码不起作用。我尝试通过将其作为 xml 代码行运行来对其进行测试。最后提供了此错误的屏幕转储。

我正在寻找有关如何将其从 C# 传递到 Oracle 以实现将这些记录插入 Oracle 表的结果的解决方案。如果您能帮助我在 Oracle 和 C#.NET 上解决这个问题,我将不胜感激。

C#.NET 端代码如下:

public class DSelect
{
  public string Installation { get; set; }
  public int Account { get; set; }
  public int BusinessNumber { get; set; }
  public long Sysd { get; set; }        
  public decimal LocX { get; set; }        
  public string Type { get; set; }
  public string Wattage { get; set; }
  public decimal ALen { get; set; }
  public int LWatt { get; set; }
  public string Tempr { get; set; }
  public DateTime CreatedDate { get; set; }       
}

List<DSelect> listDSelect = new List<DSelect>();

.... Reading an excel worksheet row in a loop and building my list. There can be between 500 to 1000 rows of data in the worksheet

var deSel= new DSelect();
deSel.Installation  = "install1";
.................................
listDSelect.Add(deSel)

XmlSerializer serializer = new XmlSerializer(typeof(List<DSelect>));

var stringwriter = new System.IO.StringWriter();

serializer.Serialize(stringwriter, listDSelect);

传递给存储过程以插入到 Oracle 数据库 12c 中的表中。

  1. 我想将整个列表作为对象传递给 oracle 存储过程。
  2. 在 oracle 存储过程中接收它并将其插入到表中。

在 SQL Developer 中失败的测试代码:

DECLARE
  p_AdditionRequest varchar2(30000); -- CLOB;
  t_xmlType SYS.XMLTYPE;
BEGIN    
  p_AdditionRequest:= '<?xml version="1.0" encoding="utf-16"?>
<ArrayOfDetailedSelection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <DetailedSelection>
    <Installation>645805</InstallationNumber>
    <AccountNumber>33170019251</AccountNumber>
  </DetailedSelection>
</ArrayOfDetailedSelection>';
  --t_xmlType := sys.xmltype.createxml(p_AdditionRequest); 

  SELECT InstallationNumber, AccountNumber (
  SELECT ExtractValue(column_value, '/DetailedSelection/InstallationNumber') InstallationNumber,
         ExtractValue(column_value, '/DetailedSelection/AccountNumber') AccountNumber         
  FROM TABLE(XMLSequence(XMLTYPE(p_AdditionRequest).EXTRACT('/ArrayOfDetailedSelection/DetailedSelection')))
       )
END;
/

标签: c#sql.netoracleoracle11g

解决方案


您的 SQL 代码很接近,但您有几个错误。首先,您在 Installation 和 InstallationNumber 之间不一致,其次您缺少 INTO。我创建了一个测试表来保存数据,但是这样的东西应该可以工作:

DECLARE
  p_AdditionRequest varchar2(30000); -- CLOB;
BEGIN    
  p_AdditionRequest:= '<?xml version="1.0" encoding="utf-16"?>
<ArrayOfDetailedSelection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <DetailedSelection>
    <InstallationNumber>645805</InstallationNumber>
    <AccountNumber>33170019251</AccountNumber>
  </DetailedSelection>
</ArrayOfDetailedSelection>';

INSERT INTO TESTDETAILEDSECTION
  SELECT InstallationNumber, AccountNumber
  FROM (
  SELECT ExtractValue(column_value, '/DetailedSelection/InstallationNumber') InstallationNumber,
         ExtractValue(column_value, '/DetailedSelection/AccountNumber') AccountNumber         
  FROM TABLE(XMLSequence(XMLTYPE(p_AdditionRequest).EXTRACT('/ArrayOfDetailedSelection/DetailedSelection')))
       );
END;
/

但是,我更喜欢对 SELECT 使用稍微不同的语法,因此:

INSERT INTO TESTDETAILEDSECTION
  SELECT xt.INSTALLATION, xt.ACCOUNTNUMBER FROM 
XMLTABLE('/ArrayOfDetailedSelection/DetailedSelection' PASSING xmlType(p_AdditionRequest)
  COLUMNS 
  "INSTALLATION" varchar(20) PATH 'InstallationNumber',
  "ACCOUNTNUMBER" varchar(20) PATH 'AccountNumber') xt;

后者的好处是可以在解析时设置xml中字段的数据类型。(我假设 InstallationNumber 和 AccountNumber 都是 varchars)。您的怀疑也是正确的;从 c# 传递时,您需要使用clob. OracleDbType这里有一个小提示,从 c# 开始,您需要将OracleDbTypeEx参数设置为OracleDbTyp.Clob.


推荐阅读