Преобразование DataTable в IEnumerable <t> в ASP.NET Core 2.0

Мне нужно создать "IEnumerable из DataTable, который я получаю в качестве входа от другой системы. Следующий код работал в ASP.NET 4.6.1.

public static IEnumerable<UserAssignmentDto> StaffAssignmentsUsingStoredProcedure(System.Data.DataTable dataTable)
    {
        var data = dataTable.AsEnumerable().Select(row =>
            new UserAssignmentDto
            {
                Id = ((string)row["AssignmentNumber"]),
                Position = (string) row["EsrPositionTitle"],

            });

        return data;
    }

Тем не менее, "DataTable" больше не содержит определения для "AsEnumerable" в ASP.NET Core 2.0.

Какой был бы самый эффективный способ генерации "IEnumerable", который мне нужен?

Ответ 1

Одна из самых эффективных вещей, которую вы можете сделать, - это написать код для итерации самостоятельно, используя цикл for вместо LINQ, просто перебирайте строки DataTable и IEnumerable<UserAssignmentDto>/гидратируйте возвращаемое значение метода IEnumerable<UserAssignmentDto> "вручную".

Поскольку DataTable не реализует Enumerator в.NET 2.0 Ядра вам нужно будет использовать "обычный" for цикла для перебора строк. Вы не можете использовать foreach потому что DataTable не реализовал IEnumerable в.NET Core 2.0.

public static IEnumerable<UserAssignmentDto> StaffAssignmentsUsingStoredProcedure(System.Data.DataTable dataTable)
{
    var retList = new List<UserAssignmentDto>();

    for(int i = 0; i < dataTable.Rows.Count; i++)
    {
          var row = dataTable.Rows[i];

          var temp = new UserAssignmentDto(){
              Id = row["AssignmentNumber"],
              Position = row["EsrPositionTitle"]
          };

          retList.Add(temp);     
    }

    return retList;
}

Ответ 2

Вот общая функция расширений AsEnumerable, чтобы имитировать то, что сделал классический AsEnumerable(), вернуть коллекцию DataRows с помощью Enumerable из DataTable. Может быть полезным для тех, кто хочет имитировать объем рефакторинга, необходимый при переносе кода на ядро .net.

    public static IEnumerable<DataRow> AsEnumerable(this DataTable table)
    {
        for (int i = 0; i < table.Rows.Count; i++)
        {
            yield return table.Rows[i];
        }
    }

Ответ 3

Не для наиболее эффективного, но для альтернативы, вы можете использовать метод Select:

DataRow[] rows= dataTable.Select();

И теперь у вас есть IEnumerable строк. Этот метод может помочь кому-то:

public static List<T> ConvertDataTableToGenericList<T>(DataTable dt)
{
     var columnNames = dt.Columns.Cast<DataColumn>()
            .Select(c => c.ColumnName)
            .ToList();

     var properties = typeof(T).GetProperties();
     DataRow[] rows= dt.Select();
     return rows.Select(row =>
     {
          var objT = Activator.CreateInstance<T>();
          foreach (var pro in properties)
          {
              if (columnNames.Contains(pro.Name))
                   pro.SetValue(objT, row[pro.Name]);
          }

          return objT;
     }).ToList();
}

Ответ 4

Правильный пакет nuget для .net core 2 - System.Data.DataSetExtensions

Ответ 6

Эффективность зависит от варианта использования. Ответ Brians хорош, если вам нужен весь результат. Его можно улучшить, предварительно распределяя потенциал для списка, чтобы избежать изменения размера или изменения в Array, но в целом это хорошо. Я бы скорее вернул List или Array, чтобы более четко показать, что он делает, но это мой личный выбор. Он сохраняет состояние DataTable в момент его вызова, что может быть хорошим или плохим в зависимости от того, что вам нужно.

Если есть вероятность, что вам не понадобятся все элементы или, возможно, вы не будете перечислять IEnumerable вообще, может быть более эффективным создание реального счетчика:

public static IEnumerable<UserAssignmentDto> StaffAssignmentsUsingStoredProcedure(System.Data.DataTable dataTable)
        {
            foreach (DataRow row in dataTable)
            {
               yield return new UserAssignmentDto()
                {
                    Id = row["AssignmentNumber"],
                    Position = row["EsrPositionTitle"]
                };               
            }
        }

Но это не самый быстрый вариант. Вы можете избежать выделения нового объекта каждый раз, когда вы получаете. Вы можете возвращать один и тот же объект каждый раз, просто задайте свойства соответствующим образом. У этого есть очевидный недостаток, что вы не можете хранить объекты из этого IEnumerable для будущего использования, но иногда вам это не нужно.

public static IEnumerable<UserAssignmentDto> StaffAssignmentsUsingStoredProcedure(System.Data.DataTable dataTable)
        {
            UserAssignmentDto ret = new UserAssignmentDto();
            foreach (DataRow row in dataTable)
            {
                ret.Id = row["AssignmentNumber"];
                ret.Position = row["EsrPositionTitle"];
                yield return ret;
            }
        }

Ответ 7

Вы можете использовать myDataTable.Select();, он возвращает массив всех DataRow