web-dev-qa-db-fra.com

Conversion de DataTable en IEnumerable <T> dans ASP.NET Core 2.0

Je dois générer un IEnumerable à partir d'un DataTable que je reçois en tant qu'entrée d'un autre système. Le code suivant a fonctionné dans 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;
    }

Toutefois, "DataTable" ne contient plus de définition de "AsEnumerable" dans ASP.NET Core 2.0. 

Quel serait le moyen le plus efficace de générer le "IEnumerable" dont j'ai besoin?

6
Roddy Balkan

Une des choses les plus efficaces que vous puissiez faire est d’écrire vous-même le code de l’itération, en utilisant une boucle for à la place de LINQ, en effectuant une itération sur les lignes DataTable et en générant/hydratant la valeur de retour de la méthode IEnumerable<UserAssignmentDto> «à la main».

Comme DataTable n’implémente pas d’énumérateur dans .NET Core 2.0, vous devrez utiliser une boucle "normale" for pour effectuer une itération sur les lignes. Vous ne pouvez pas utiliser foreach car DataTable n'a pas implémenté IEnumerable dans .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
Brian Ogden

Voici une fonction d'extension générique AsEnumerable pour imiter ce que le classique AsEnumerable () a fait: renvoyer une collection Enumerable de DataRows à partir d'un DataTable. Peut être utile pour quelqu'un qui souhaite minimiser la quantité de refactoring nécessaire lors du transfert de son code vers .net.

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

AsEnumerable () existe dans .NET Core 2.0, il vous suffit d’ajouter une référence à System.Data.DataExtensions comme indiqué dans la réponse à une question similaire . LINQ to DataSet, DataTable.AsEnumerable () non reconnu

3
r2k83

Pas le plus efficace, mais pour une alternative, vous pouvez utiliser la méthode Select:

DataRow[] rows= dataTable.Select();

Et maintenant, vous avez un IEnumerable de lignes. Cette méthode peut aider quelqu'un:

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= dataTable.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();
}
2
Naser Yousefi

L'efficacité dépend du cas d'utilisation. La réponse de Brians est bonne si vous avez besoin du résultat complet. Il peut être amélioré en préallouant la capacité de List afin d’éviter le redimensionnement ou le passage à Array, mais c’est généralement bon. Je préférerais que List ou Array montre plus explicitement ce qu’il fait, mais c’est mon choix personnel. Il conserve l’état de DataTable au moment où il est appelé, ce qui peut être bon ou mauvais en fonction de vos besoins.

S'il y a une chance que vous n'ayez pas besoin de tous les éléments ou peut-être que vous n'énumériez pas IEnumerable, il peut être plus efficace de construire un véritable énumérateur:

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

Mais ce n'est pas encore l'option la plus rapide. Vous pouvez éviter d'allouer un nouvel objet à chaque fois que vous cédez. Vous pouvez retourner le même objet à chaque fois, définissez simplement les propriétés en conséquence. L’inconvénient évident est que vous ne pouvez pas stocker d’objets de ce type IEnumerable pour une utilisation ultérieure, mais vous n’avez parfois pas besoin de cela.

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;
            }
        }
1
Antonín Lejsek