简体   繁体   中英

Convert DataTable to IEnumerable<T> in ASP.NET Core 2.0

I need to generate an 'IEnumerable from a DataTable that I receive as an input from another system. The following code worked in 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;
    }

However, 'DataTable' no longer contains a definition for 'AsEnumerable' in ASP.NET Core 2.0.

What would be the most efficient way to generate the 'IEnumerable' that I need?

Here is a generic AsEnumerable extension function to mimic what the classic AsEnumerable() did, return an Enumerable collection of DataRows from a DataTable. Can be useful for someone that wishes to mimimize the amount of refactoring needed when porting their code to .net core.

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

.net core 2 的正确 nuget 包是System.Data.DataSetExtensions

Not about most efficient but for an alternative, you can use the Select method:

DataRow[] rows= dataTable.Select();

And now you have an IEnumerable of rows. This method may help someone:

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

One of the most efficient things you can do is write the code for the iteration yourself, using a for loop instead of LINQ, just iterate over the DataTable rows and build/hydrate the IEnumerable<UserAssignmentDto> method return value "by hand".

Since there DataTable does not implement an Enumerator in .NET Core 2.0 you will need to use a "regular" for loop to iterate over the rows. You cannot use foreach because DataTable has not implemented IEnumerable in .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;
}

AsEnumerable() does exist in .NET Core 2.0, you just need to add a reference to System.Data.DataExtensions as mentioned in the answer to a similar question. LINQ to DataSet, DataTable.AsEnumerable() not recognized

Efficiency depends on use case. The Brians answer is good if you need the whole result. It can be improved, by preallocating capacity for List to avoid resizing or changing to Array, but generally it is good. I would rather return List or Array to more explicitely show what it does, but that is my personal choice. It conserves state of DataTable at the moment it is called, which may be good or bad depending on what you need.

If there is a chance you would not need all items or maybe you would not enumerate the IEnumerable at all, it may be more efficient to construct real enumerator:

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

But it is not the fastest option still. You may avoid allocating new object every time you yield. You can return the same object every time, just set properties accordingly. It has the obvious drawback that you can not store objects from such IEnumerable for future use, but sometimes you do not need that.

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

You can use myDataTable.Select(); it returns an array of all DataRow

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM