2009-06-03 5 views
2

Je cherche à faire quelque chose comme ceci:recherche suggesions re: l'accès aux données et peuplant Liste/arraylist/Liste

  1. enregistrements d'accès dans db avec une datareader. Je ne saurai pas combien de disques reviendront - entre 1 et 300 la plupart du temps. Les données ressembleront à ceci "0023", "Eric", "Harvest Circle", "Boston" pour chaque enregistrement.
  2. Je voulais remplir immédiatement quelque chose (tableau, liste?) Et fermer la connexion.
  3. Transmettez l'objet rempli à mon service Web où je vais le convertir en JSON avant de l'envoyer au client.

Le problème que je rencontre est quel objet/objets à remplir avec les données du lecteur de données. J'ai commencé à utiliser une ArrayList (et j'ai maintenant lu sur l'utilisation de List à la place), mais bien que je puisse récupérer tous les enregistrements (dans ce cas juste 2 Items), je ne pouvais pas accéder aux champs individuels. etc).

Entrez Plan B: pour chaque enregistrement dans le lecteur de données, ajoutez les valeurs de colonnes individuelles à un tableau, puis ajoutez chaque tableau à la liste. Je pense que cela fonctionnera, mais je ne suis pas sûr de savoir comment instancier un tableau quand je ne sais pas combien il faudrait instancier. En d'autres termes, je ferais normalement cette chaîne [] myarray = new string [] {"eric", "boston", "etc"}; Mais si j'ai plusieurs enregistrements, à quoi cela ressemble-t-il? Remplir le tableau, ajouter à la liste, effacer le tableau original, puis le repeupler, l'ajouter à la liste, etc.

Toute aide serait grandement appréciée! Aussi, je suis très ouvert à d'autres façons de le faire.

Merci!

Répondre

5

La réponse standard ici, à l'aide d'un calque de persistance comme Entity Framework, est de créer des classes «entité» avec les champs dont vous avez besoin. Quelque chose comme:

class Customer 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

... puis de les rassembler dans une collection quelconque. Un List<Customer> est bien.

List<Customer> customers = new List<Customer>(); 

string connectionString = null; 
using (SqlConnection connection = new SqlConnection(connectionString)) 
{ 
    connection.Open(); 
    SqlCommand command = new SqlCommand("GetData"); 
    using (IDataReader reader = command.ExecuteReader()) 
    { 
     while (reader.Read()) 
     { 
      Customer c = new Customer(); 
      c.Id = (int)reader["ID"]; 
      c.FirstName = (string)reader["FirstName"]; 
      c.LastName = (string)reader["LastName"]; 
      customers.Add(c); 
     } 
    } 
} 

Si vous avez un grand nombre de tables ou une liste modifiable de champs, cela peut être difficile à maintenir. Pour les tâches simples, cependant, cela fonctionne bien.

+0

Merci pour cela - je ne pensais pas que je devrais créer une classe pour stocker les valeurs, mais il semble que c'est la voie à suivre! – ericgr

0

Créer un objet qui a des propriétés qui correspond aux champs qui vont revenir dans le datareader:

public class MyClass 
{ 
    public int Id{get;set;} 
    public string Name{get;set;} 
    .... 
} 

Ensuite, foreach sur tous les résultats dans le datareader. Ensuite, créez un objet de ce type et définissez toutes les propriétés avec les valeurs dans les colonnes pour ces enregistrements. Ensuite, ajoutez-les à une liste < MyClass>.

0

Je vous recommande de regarder dans LINQ to SQL (si vous avez une base de données très simple), ou NHibernate (si vous avez une base de données plus complexe). Ce sont des mappeurs OR qui peuvent grandement simplifier le processus de transformation d'une requête SQL en objets pouvant être utilisés dans votre domaine, les services passés, etc.

1

La réponse de Michael est généralement la meilleure. Une fois que les choses commencent à se compliquer, vous pouvez ajouter des abstractions (vous aurez besoin d'usines d'objets qui prennent en compte les lecteurs sql et d'autres choses amusantes) et commencer à faire circuler des objets et des usines.J'ai trouvé cette stratégie très utile, et une classe datalayer bien écrite peut être utilisée dans tous vos projets liés à la base de données. Une alternative est d'utiliser un SqlDataAdapter et de convertir votre sortie en DataSet. D'après mon expérience, c'est assez compliqué et généralement une très mauvaise idée. Cela dit, si vous avez tendance à saisir un morceau de données, à le manipuler (mettre à jour des pièces, ajouter de nouvelles pièces, supprimer des pièces), cela peut être une bonne façon de le faire en mémoire avec du code C#. Réfléchissez à deux fois avant d'essayer cette technique. Cela équivaut essentiellement à saisir des données et à remplir une liste de lignes, bien qu'un DataSet ait un peu plus de contenu qu'un tableau (par exemple, il inclut des noms de colonnes).

J'ai l'impression que l'utilisation d'un SqlDataAdapter pour remplir une DataSet est la réponse la plus proche de vous donner ce que vous demandez dans votre question, mais la pire réponse en termes de vous donner ce dont vous avez réellement besoin.

+0

Merci, Brian. J'ai utilisé beaucoup de jeux de données typés dans le passé (mon .net est actuellement très rouillé). En raison de ce que j'espère sera l'utilisation de haut niveau, j'essaie d'éviter la surcharge d'un ensemble de données, sauf pour insérer/mettre à jour/supprimer. Toutes les sélections utiliseront un lecteur de données à des fins de rapidité. – ericgr

0

Je pense qu'une solution simple est ici en ordre. Je voudrais créer un DataAdapter, puis remplir un DataTable avec les données. Vous pouvez ensuite fermer la connexion, et la table de données restera peuplée, puisque, contrairement à ADO, ADO.NET par défaut aux jeux d'enregistrements déconnectés.

Vous pouvez accéder facilement aux données par nomchamp, par exemple,

myDataTable["FirstName"].ToString() 

Si tout ce que vous allez faire est de convertir les données en JSON, créant ainsi un objet qui mappe les propriétés des champs de base de données semble inutile puisque ADO.NET vous donne ce hors de la boîte.

3

Les chances sont que vous n'avez pas besoin d'une classe concrète comme List ou tableau. Un IEnumerable est probablement assez bon. Dans cet esprit, ceci est mon modèle préféré:

public IEnumerable<IDataRecord> GetData() 
{ 
    using (var cn = getOpenConnection(connectionString)) 
    using (var cmd = new SqlCommand("GetData", cn)) 
    using (var rdr = cmd.ExecuteReader()) 
    { 
     while (rdr.Read()) 
     { 
      yield return (IDataRecord)rdr; 
     } 
    } 
} 

Vous pouvez également modifier que pour créer des objets d'affaires fortement typées, mais je garde généralement que dans une couche séparée/niveau. Les blocs d'itérateur effectuent une évaluation paresseuse/une exécution différée et donc le niveau de traduction supplémentaire ne nécessite pas une itération supplémentaire des résultats.

Il y a une astuce avec ce code. Vous devez être sûr de copier les données de chaque enregistrement dans un objet réel à un moment donné. Vous ne pouvez pas vous lier directement, ou vous obtiendrez des résultats potentiellement surprenants. Une variante que j'utilise le plus souvent consiste à rendre la méthode générique et nécessite un argument Func<IDataRecord, T> pour traduire chaque enregistrement lors de sa lecture.

+0

Je n'ai jamais envisagé de conserver les IDataRecords renvoyés par un DataReader. Je vais devoir m'en souvenir ... –

+0

Je n'en sais pas assez pour que ce soit la réponse acceptée, mais je vais certainement lui donner un tourbillon. Merci, Joel! – ericgr

+1

@Michael Petrotta: la beauté de ceci est qu'il ne "retient" rien. Un seul objet est toujours en mémoire à la fois. Le compromis est potentiellement garder votre connexion db active un peu plus longtemps. –

Questions connexes