【问题标题】:Bulk insert of ICollection into an Oracle Table将 ICollection 批量插入到 Oracle 表中
【发布时间】:2021-11-11 01:46:37
【问题描述】:

我正在根据来自 Nswag 工作室的规范编写 API 客户端。我可以使用提供的 client.PlansAsync(apikey).GetAwaiter().GetResult() 检索该数据,但我正在努力将返回的 ICollection 转换为能够批量插入 Oracle 数据库表的数据。

我试图创建一个DataTable,但在转换为数据表的过程中,抛出了一个异常。我怀疑它与集合中的可为空类型有关。

我的猜测是我应该尝试使用 Entity Framework 进行插入,但对于这个特定的客户端来说,添加所有额外的 EF Core 内容似乎是多余的。

我觉得 Oracle 批量复制方法非常适合我的意图,但我一直遇到上面列出的问题。

任何帮助将不胜感激。

TIA

编辑:这是有问题的代码。

//first in the calling class
ICollection<Plans> plansFromApi = client_.PlansAsync(apiKey).GetAwaiter().GetResult();

ListToDatTable listToDt = new();
List<Plans> ps = plansFromApi.ToList();
DataTable dt = listToDt.ToDataTable<Plans>(ps);


//second the List to Datatable class

public class ListToDataTable
{
    public DataTable ToDataTable<T>(List<T> items)
    {
        DataTable dataTable = new(typeof(T).Name);
        PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        foreach(T item in items)
        {
            var values = new object[Props.Length];
            for(int i = 0; i < Props.Length; i++)
            {
                values[i] = Props[i].GetValue(item);
            }
            //line where the exception is thrown
            //System.ArgumentException: 'Input array is longer than the number of columns in this table.'
            dataTable.Rows.Add(values);
         }
     }
}

编辑 2: 这是来自 Nswag 工作室的内容。这只是我需要检索的 15 个数据集之一。这不是我目前正在测试的那个,因为它有 25 个属性,所以为简洁起见,我将包含一个较小的属性。最后它们都将是相同的,因为它们都将以完全相同的方式进行处理,是的,我也使用此数据集进行了测试,并收到了相同的异常。

[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.5.2.0 (Newtonsoft.Json v12.0.0.0)")]
    public partial class ContactGroupedManufacturer
    {
        [Newtonsoft.Json.JsonProperty("lastContacted", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public System.DateTimeOffset? LastContacted { get; set; }
    
        [Newtonsoft.Json.JsonProperty("vendorContactId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public int VendorContactId { get; set; }
    
        [Newtonsoft.Json.JsonProperty("ManufacturerId", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public int ManufacturerId { get; set; }
    
        [Newtonsoft.Json.JsonProperty("website", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
        public string Website { get; set; }
    
    
    }

这里有几行数据:

lastContacted vendorContactId manufacturerId website
6575 1848
6599 2693
6604 8878 06/08/2018
6692 6879
6930 4040 some url

2021 年 11 月 10 日更新:我发现了一个名为 MoreLinq 的 NuGet 包,其中包含一个扩展方法,用于处理到 DataTable 的转换。

ICollection<ActionPlans> actionPlans = client.ActionPlansAsync(apiKey).GetAwaiter().GetResult();
_logger.LogInformation(${actionPlans.Count} APs returned");

DataTable actionPlansDt = actionPlans.ToDataTable();

【问题讨论】:

  • 那么代码在哪里,包括异常在内都不起作用?假设我把猜测的裤子留在了洗衣房里。
  • @Marco 昨天我发布了这个,但我已经添加了它。
  • 我们都会时不时地拥有这些。现在请添加提到的异常以及它发生的位置。加分,如果你能给出一个表模式和一两行数据来重现。
  • 异常发生在语句dataTable.Rows.Add(values)
  • 给定的异常很清楚,您的数据表中没有足够的列。检查您有多少列,以及您尝试将多少属性放入该表中。您也可以尝试自己从属性中处理DataTable中列的创建过程,这样您就可以确定要处理哪些属性。

标签: c# oracle


【解决方案1】:

您可以将 IEnumerable 包装在 IDataReader 中以传递给 BulkCopy 方法。参见例如: ObjectDataReader

一旦您拥有 IDataReader,请将其传递给 OracleBulkCopy.WriteToServer(IDataReader) 请参阅 OracleBulkCopy

【讨论】:

  • 这适用于 Oracle 吗?查看 repo 中的代码,它似乎是针对 SQL Server 的。
  • 是的 OracleBulkCopy 就像 SqlBulkCopy 一样工作。查看更新的答案。
【解决方案2】:

您可能对 DataTable 中的列数有疑问。 试试这个代码:

public class ListToDataTable
{
    public DataTable ToDataTable<T>(List<T> items)
    {
        DataTable dataTable = new DataTable();
        PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
        bool columnsAlreadyCreated=false;
        foreach(T item in items)
        {
            if (columnsAlreadyCreated==false)
            {
              for(int i = 0; i < Props.Length; i++)
              {
         dataTable.Columns.Add(Props[i].Name,Nullable.GetUnderlyingType(
         Props[i].PropertyType) ?? Props[i].PropertyType);
              }
              columnsAlreadyCreated=true;
            }
            var values = new object[Props.Length];
            for(int i = 0; i < Props.Length; i++)
            {
                values[i] = Props[i].GetValue(item);
            }
            //line where the exception is thrown
            //System.ArgumentException: 'Input array is longer than the number of columns in this table.'
            dataTable.Rows.Add(values);
         }
     }
}

【讨论】:

  • 我尝试修改代码,但我仍然遇到nullable 类型的问题。当我到达具有System.Nullable... 的属性时,我得到了异常Dataset does not support System.Nullable
  • @RobM 好的,这是另一种类型的异常。我修改了我的代码,更改了向数据源添加列的通道:dataTable.Columns.Add(Props[i].Name,Nullable.GetUnderlyingType( Props[i].PropertyType) ?? Props[i].PropertyType); 你现在应该试试。
  • @RobM 你搞定了吗?
  • 我最终找到了一个名为 morelinq 的 NuGet 包,它有一个基于ICollection 创建数据库的扩展方法。
猜你喜欢
  • 1970-01-01
  • 2012-01-17
  • 2017-09-30
  • 1970-01-01
  • 1970-01-01
  • 2010-09-25
  • 2011-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多