web-dev-qa-db-fra.com

Remplissez un tableau (ou un tableau) à partir de SqlDataReader

Existe-t-il un moyen de remplir un tableau via un SqlDataReader (ou tout autre objet C # ADO.NET) sans parcourir tous les éléments? J'ai une requête qui renvoie une seule colonne, et je veux la mettre dans un tableau de chaînes (ou ArrayList, ou List, etc.).

23
ristonj

C'est possible. Dans .NET 2.0+, SqlDataReader hérite de DbDataReader, qui implémente IEnumerable (non générique). Cela signifie que vous pouvez utiliser LINQ:

List<string> list = (from IDataRecord r in dataReader
                     select (string)r["FieldName"]
                    ).ToList();

Cela dit, la boucle est toujours là, elle est juste cachée dans Enumerable.Select, plutôt que d'être explicite dans votre code.

48
Pavel Minaev

Non, étant donné que SqlDataReader est un flux de lignes en lecture seule vers l'avant uniquement à partir d'une base de données SQL Server, le flux de lignes sera bouclé, qu'il soit explicitement dans votre code ou masqué dans une implémentation de structure (comme [DataTable's Load).

Cela ressemble à l'utilisation d'une liste générique, puis le renvoi de la liste sous forme de tableau serait une bonne option. Par exemple,

List<int> list = new List<int>();

using (SqlDataReader reader = cmd.ExecuteReader())
{
    while (reader.Read())
    {
         list.Add(reader.GetInt32(0));
    }    
}
return list.ToArray();

En réponse à votre commentaire, appeler ToArray () peut être une surcharge, cela dépend. Avez-vous besoin d'un tableau d'objets pour travailler avec ou une collection générique (telle que List<T> ou ReadOnlyCollection<T>) être plus utile?

11
Russ Cam

Apparemment, depuis .NET 1.1 SqlDataReader avait la méthode suivante :

int size;
object[] data = new object[]{};
size = reader.GetValues(data);

Cela remplit data avec les valeurs de la ligne de lecture actuelle, en affectant en taille le nombre d'objets qui ont été placés dans le tableau.

6
JNF

Étant donné que toute implémentation de IDataReader (SqlDataReader incluse) sera par définition un lecteur en avant uniquement, il n'y a aucun moyen de le faire sans bouclage. Même s'il y avait une méthode de bibliothèque de framework pour ce faire, elle devrait parcourir le lecteur, comme vous le feriez.

4
Andrew Hare

L'OP d'origine a demandé Array, ArrayList ou List. Vous pouvez également renvoyer Array. Appelez simplement la méthode .ToArray () et affectez-la à un tableau précédemment déclaré. Les tableaux sont très rapides lorsqu'il s'agit d'énumérer chaque élément. Beaucoup plus rapide qu'une liste si la liste contient plus de 1000 éléments. Vous pouvez revenir à Array, List ou Dictionary.

ids_array = (from IDataRecord r in idReader 
select (string)r["ID"]).ToArray<string>();  

De plus, si vous utilisez une recherche de clés par exemple, vous pouvez envisager de créer un objet HashSet avec d'excellentes performances de recherche si vous vérifiez simplement une liste par rapport à une autre pour déterminer si une clé d'éléments existe dans l'objet HashSet. exemple:

 HashSet<string> hs = new HashSet<string>( 
(from IDataRecord r in idReader select (string)r["ID"]).AsEnumerable<string>() );
1
RickIsWright

Si vous lisez votre SqlDataAdapter dans un DataTable:

DataTable dt as DataTable; 
dt.fill(data);

Ensuite, vous pouvez utiliser certains des jouets dans System.Data.DataSetExtensions comme référencé dans la réponse de Joel Muller à cette question.

Dans utilise un peu de Linq, vous aurez donc net .Net 3.5 ou supérieur.

1
Rob Allen

Vous devez faire une boucle, mais il existe des projets qui peuvent le simplifier. Essayez également de ne pas utiliser ArrayList, utilisez plutôt List.

Vous pouvez commander FluentAdo pour un: http://fluentado.codeplex.com

    public IList<UserAccount> List()
    {
        var list = new FluentCommand<UserAccount>("SELECT ID, UserName, Password FROM UserAccount")
            .SetMap(reader => new UserAccount
            {
                ID = reader.GetInt("ID"),
                Password = reader.GetString("Password"),
                UserName = reader.GetString("UserName"),
            })
            .AsList();

        return list;
    }
0
Chris Brandsma