Массовая вставка ICollection в таблицу Oracle

#c# #oracle

Вопрос:

Я пишу клиент API из спецификации, предоставленной Nswag studio. Я могу получить эти данные, используя предоставленные client.PlansAsync(apikey).GetAwaiter().GetResult() , но я изо всех сил пытаюсь превратить возвращенную ICollection во что-то, что я могу массово вставить в таблицу базы данных Oracle.

Я попытался создать DataTable , но во время преобразования в DataTable генерируется исключение. Я подозреваю, что это как-то связано с обнуляемыми типами в коллекции.

Я предполагаю, что я должен пытаться выполнять вставки с использованием Entity Framework, но, похоже, добавление всех дополнительных компонентов ядра EF является излишним для этого конкретного клиента.

Я чувствую, что методы массового копирования 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; }
    
    
    }
 

Здесь несколько строк данных:

Последний контакт vendorContactId Идентификатор производителя Веб-сайт
6575 1848
6599 2693
6604 8878 06/08/2018
6692 6879
6930 4040 некоторый URL

ОБНОВЛЕНИЕ 2021/11/10: я нашел пакет NuGet с именем MoreLINQ, который содержал метод расширения, который обрабатывал преобразование в a DataTable .

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

DataTable actionPlansDt = actionPlans.ToDataTable();
 

Комментарии:

1. Итак, где же код, который не работает, включая исключение? Предположим, я оставил свои догадки — брюки в прачечной.

2. @Marco У меня был момент вчера, когда я опубликовал это, но я добавил его.

3. У всех нас это бывает время от времени. Теперь, пожалуйста, добавьте упомянутое исключение и где оно встречается. Бонусные баллы, если вы можете предоставить схему таблицы и одну или две строки данных для воспроизведения.

4. Исключение происходит в инструкции dataTable.Rows.Add(values)

5. Данное исключение достаточно ясно, у вас недостаточно столбцов в вашей таблице данных. Проверьте, сколько столбцов у вас есть, и сколько свойств вы пытаетесь поместить в эту таблицу. Вы также можете попытаться самостоятельно управлять процессом создания столбцов в DataTable из свойств, чтобы вы были уверены, какие свойства вы хотите обрабатывать.

Ответ №1:

Вы можете обернуть IEnumerable в IDataReader для перехода к методу BulkCopy. См., например: ObjectDataReader

Как только у вас будет IDataReader, передайте его для OracleBulkCopy.WriteToServer(IDataReader) просмотра OracleBulkCopy.

Комментарии:

1. Будет ли это работать с Oracle? Глядя на код в репозитории, он, похоже, предназначен для SQL Server.

2. Да, OracleBulkCopy работает так же, как SqlBulkCopy. Смотрите Обновленный ответ.

Ответ №2:

Вероятно, у вас проблема с количеством столбцов в таблице данных. Попробуйте этот код:

 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);
         }
     }
}
 

Комментарии:

1. Я попытался изменить код, но я все еще сталкиваюсь с проблемой с nullable типом. Когда я добираюсь до свойства, которое имеет System.Nullable... , я получаю исключение Dataset does not support System.Nullable

2. @RobM хорошо, это другой тип исключения. Я изменил свой код, изменил полосу, которая добавляла столбцы в источник данных: dataTable.Columns.Add(Props[i].Name,Nullable.GetUnderlyingType( Props[i].PropertyType) ?? Props[i].PropertyType); Вы должны попробовать это сейчас.

3. @RobM у тебя это работает?

4. Я закончил поиск пакета NuGet с именем morelinq, который имел метод расширения, который создавал базу данных на основе ICollection .