2009-04-02 7 views
7

Comment puis-je convertir un DataTable en liste?DataTable to List <object>

J'ai inclus du code ci-dessous à la fois dans C# et VB.NET, le problème avec ces deux choses est que nous créons un nouvel objet pour renvoyer les données, ce qui est très coûteux. Je dois retourner une référence à l'objet.

L'objet DataSetNoteProcsTableAdapters.up_GetNoteRow met en œuvre l'interface INote.

J'utilise ADO.NET, avec .NET 3.5

C# code

public static IList<INote> GetNotes() 
{ 
    DataSetNoteProcsTableAdapters.up_GetNoteTableAdapter adapter = 
     new DataSetNoteProcsTableAdapters.up_GetNoteTableAdapter(); 
    DataSetNoteProcs.up_GetNoteDataTable table = 
     new DataSetNoteProcs.up_GetNoteDataTable(); 

    IList<INote> notes = new List<INote>(); 

    adapter.Connection = DataAccess.ConnectionSettings.Connection; 
    adapter.Fill(table); 

    foreach (DataSetNoteProcs.up_GetNoteRow t in table) { 
     notes.Add((INote)t); 
    } 

    return notes; 
} 

code VB.NET

Public Shared Function GetNotes() As IList(Of INote) 
    Dim adapter As New DataSetNoteProcsTableAdapters.up_GetNoteTableAdapter 
    Dim table As New DataSetNoteProcs.up_GetNoteDataTable 

    Dim notes As IList(Of INote) = New List(Of INote) 

    adapter.Connection = DataAccess.ConnectionSettings.Connection 
    adapter.Fill(table) 

    For Each t As DataSetNoteProcs.up_GetNoteRow In table 
     notes.Add(CType(t, INote)) 
    Next 

    Return notes 
End Function 
+0

Toute raison pour laquelle vous ne l'utilisez LINQ2SQL pour cela? –

+0

Dup: http://stackoverflow.com/questions/545328/datatable-to-generic-list-memory-leak/545429#545429 –

+0

Le client ne souhaite généralement pas utiliser LINQ2SQL ou LINQ. Merci pour le lien, ça va beaucoup aider. Je vais courir quelques fois et voir ce qui se passe – Coppermill

Répondre

2

Non, créer une liste n'est pas coûteux. Comparé à la création de la table de données et à l'extraction des données de la base de données, c'est très bon marché.

Vous pouvez le faire encore moins cher en créant la liste après avoir rempli la table, de sorte que vous pouvez définir la capacité initiale du nombre de lignes que vous mettrez dedans:

IList<INote> notes = new List<INote>(table.Rows.Count); 
+0

sûrement vous dire IList notes = nouvelle liste (table.Rows) si vous vous obtenez l'erreur suivante « Sub New Public (collection AsIEnumerable (de IRemarque)) ': conversions implicites de' DataRowCollection 'à' IEnumerable (Of INote) '. – Coppermill

+5

Non, il veut dire ce qu'il a écrit. Cela entraînera la définition de la liste à la taille de l'ensemble de résultats. – Jake

-1

Si les propriétés de la liste correspondent aux noms de champ Dans le datatable, vous devriez être capable de créer une sorte de routine de réflexion générique.

+0

Mais il n'est pas nécessaire de créer un nouvel objet, il doit faire référence à l'objet. Ceci est – Coppermill

0

Voulez-vous référencer les lignes de la table? Dans ce cas, vous devez utiliser la propriété DataTable.Rows.

Essayez ceci:

notes.AddRange(table.Rows); 

Si les lignes de la table à mettre en œuvre IRemarque alors cela devrait fonctionner.

Sinon, vous pouvez faire ce que vous avez fait ci-dessus:

foreach (INote note in table.Rows) 
{ 
    notes.Add(note) 
} 
+0

sur table.Rows Warning erreurs d'exécution peuvent se produire lors de la conversion « System.Data.DataRowCollection » à « System.Collections.Generic.IList (Of.INote) » Ceci génère un nouvel objet, ce qui est ce que j'essaie d'éviter – Coppermill

+0

Non, cela ne devrait pas créer de nouveaux objets. Tout ce que vous faites est de jeter l'objet à un autre type. –

1

Pourquoi ne pas passer DataTable dans la fonction au lieu de instancier? Cela contiendrait simplement une référence.

C'est trop simple, une réponse vous en vaut la peine, j'en suis sûr, mais je ne vois pas comment cela ne résoudra pas votre problème.

+0

Je suis après une IRemarque à retourner – Coppermill

1

Pas sûr si cela est ce que vous cherchez mais vous pourriez essayer quelque chose comme ça.

public class Category 
{ 
    private int _Id; 
    public int Id 
    { 
     get { return _Id; } 
     set { _Id = value; } 
    } 

    private string _Name = null; 
    public string Name 
    { 
     get { return _Name; } 
     set { _Name = value; } 
    } 

    public Category() 
    {} 

    public static List<Category> GetCategories() 
    { 
     List<Category> currentCategories = new List<Category>(); 

     DbCommand comm = GenericDataAccess.CreateTextCommand(); 
     comm.CommandText = "SELECT Id, Name FROM Categories Order By Name"; 
     DataTable table = GenericDataAccess.ExecuteSelectCommand(comm); 

     foreach (DataRow row in table.Rows) 
     { 
      Category cat = new Category(); 
      cat.Id = int.Parse(row["Id"].ToString()); 
      cat.Name = row["Name"].ToString(); 
      currentCategories.Add(cat); 
     } 
     return currentCategories; 
    } 
} 

C'est ce que j'ai fait, j'espère que cela aidera. Je ne sais pas si c'est la bonne façon de le faire, mais cela fonctionne pour ce que nous en avions besoin.

+0

Cela génère un nouvel objet, j'ai besoin du code pour référencer l'objet Catégorie cat = new Catégorie(); Presque comme Catégorie cat = (liste ) tables.Rows Mais cela ne fonctionne pas avec – Coppermill

+0

que vous pouvez mapper les attributs que vous souhaitez utiliser. c'est une approche plus grande mais pas mauvaise –

6

J'ai une autre approche qui mérite d'être examinée. C'est une méthode d'aide. Créez un fichier de classe personnalisé nommé CollectionHelper:

public static IList<T> ConvertTo<T>(DataTable table) 
    { 
     if (table == null) 
      return null; 

     List<DataRow> rows = new List<DataRow>(); 

     foreach (DataRow row in table.Rows) 
      rows.Add(row); 

     return ConvertTo<T>(rows); 
    } 

Imaginez que vous souhaitiez obtenir une liste de clients.Maintenant, vous aurez l'appelant suivant:

List<Customer> myList = (List<Customer>)CollectionHelper.ConvertTo<Customer>(table); 

Les attributs que vous avez dans votre DataTable doit correspondre à votre classe client (champs comme nom, adresse, téléphone).

J'espère que ça aide!

Pour qui sont prêts à savoir pourquoi utiliser des listes au lieu de DataTables: link text

L'échantillon complet:

http://lozanotek.com/blog/archive/2007/05/09/Converting_Custom_Collections_To_and_From_DataTable.aspx

+1

stackoverflow ne me permets que de vous donner un point, 2 ++ –

+0

cette conversion peut-elle être faite avec un lecteur de données? –

+0

Je me promenais s'il est possible d'éviter ce "must" pour les attributs de classe et les champs datatable! –