2009-04-02 28 views
7

Come si acquisisce un DataTable e lo si converte in un elenco?DataTable to List <object>

Ho incluso del codice sotto sia in C# che in VB.NET, il problema con entrambi è che creiamo un nuovo oggetto per restituire i dati, che è molto costoso. Devo restituire un riferimento all'oggetto.

L'oggetto DataSetNoteProcsTableAdapters.up_GetNoteRow implementa l'interfaccia INote.

Sto usando ADO.NET, insieme a .NET 3.5

codice C#

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

VB.NET Codice

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

Qual è il motivo per cui non lo si utilizza LINQ2SQL per questo? –

+0

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

+0

Il cliente non desidera utilizzare LINQ2SQL o LINQ in generale. Grazie per il collegamento, sarà di grande aiuto. Ho intenzione di correre qualche volta e vedere cosa succede – Coppermill

risposta

2

No, la creazione di un elenco non è costosa. Rispetto alla creazione della tabella dati e al recupero dei dati dal database, è molto economico.

Si può rendere ancora più conveniente con la creazione della lista dopo il popolamento del tavolo, in modo che è possibile impostare la capacità iniziale per il numero di righe che si metterà in esso:

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

sicuramente dire IList note = new List (table.Rows) se lo fai si ottiene il seguente errore 'Public Sub New (collezione AsIEnumerable (Of INota)) ': conversioni implicite da' DataRowCollection 'a' IEnumerable (Of INote) '. – Coppermill

+5

No, lui intende quello che ha scritto. Ciò farà sì che l'elenco sia impostato sulla dimensione del set di risultati. – Jake

-1

Se le proprietà della lista corrispondono i nomi dei campi nel datatable dovresti essere in grado di creare una sorta di routine di riflessione generica.

+0

Ma non è necessario creare un nuovo oggetto, deve fare riferimento all'oggetto. – Coppermill

0

Vuoi fare riferimento alle righe del tavolo? In tal caso, è necessario utilizzare la proprietà DataTable.Rows.

Prova questo:

notes.AddRange(table.Rows); 

Se le righe della tabella implementano INota allora questo dovrebbe funzionare.

In alternativa si potrebbe fare come avete fatto in precedenza:

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

Resta table.Rows Warning Durata errori possono verificarsi quando la conversione 'System.Data.DataRowCollection' a 'System.Collections.Generic.IList (Of.INote)' Questo genera un nuovo oggetto, che è quello che sto cercando di evitare – Coppermill

+0

No, questo non dovrebbe creare nuovi oggetti. Tutto quello che stai facendo è lanciare l'oggetto su un altro tipo. –

1

Perché non passare il DataTable in alla funzione invece di istanziare esso? Quello conterrebbe semplicemente un riferimento.

Questa è una risposta troppo semplice per te, ne sono sicuro, ma non vedo come non risolva il tuo problema.

+0

Io sono dopo un INota da restituire – Coppermill

1

Non sono sicuro se questo è quello che stai cercando ma potresti provare qualcosa di simile.

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

Questo è quello che ho fatto quindi spero che questo aiuti. Non sono sicuro se è il modo giusto per farlo, ma funziona per quello che ci serviva.

+0

Questo genera un nuovo oggetto, ho bisogno del codice per fare riferimento all'oggetto Categoria cat = new Category(); Quasi come Categoria cat = (lista ) tables.Rows Ma che non funziona – Coppermill

+0

con che è possibile mappare gli attributi che si desidera utilizzare. questo è un approccio più grande, ma non male. Lo stackoverflow –

6

Ho un altro approccio che potrebbe valere la pena dare un'occhiata. È un metodo di supporto. Creare un file di classe personalizzato denominato 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); 
    } 

Immaginate che si desidera ottenere un elenco di clienti.Ora avrete la seguente chiamante:

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

gli attributi che avete nella vostra DataTable deve corrispondere la vostra classe Customer (campi come nome, indirizzo, telefono).

Spero che aiuti!

Per chi sono disposti a sapere perché utilizzare gli elenchi invece di DataTable: link text

Il campione completo:

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

+1

mi consente solo di darti un punto, 2 ++ –

+0

questa conversione può essere eseguita con un datareader? –

+0

Stavo vagando se è possibile evitare questo "deve corrispondere" per gli attributi di classe e campi dati! –