2009-04-02 28 views
7

¿Cómo tomo una DataTable y la convierto en una lista?DataTable to List <object>

He incluido algunos códigos a continuación, tanto en C# como en VB.NET, el problema con ambos es que creamos un nuevo objeto para devolver los datos, que es muy costoso. Necesito devolver una referencia al objeto.

El objeto DataSetNoteProcsTableAdapters.up_GetNoteRow implementa la interfaz INote.

estoy usando ADO.NET, junto con .NET 3.5

código 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; 
} 

Código 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

Cualquier razón por la cual no se está usando LINQ2SQL para esto? –

+0

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

+0

El cliente no quiere utilizar LINQ2SQL o LINQ en general. Gracias por el enlace, será de gran ayuda. Voy a ejecutar algunas veces y ver qué pasa – Coppermill

Respuesta

2

No, crear una lista no es costoso. En comparación con la creación de la tabla de datos y la obtención de los datos de la base de datos, es muy barato.

Puede que sea incluso más barato en la creación de la lista después de rellenar la tabla, por lo que se puede establecer la capacidad inicial para el número de filas que se va a poner en ella:

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

seguramente quiere decir IList notas = nueva lista (table.Rows) si lo hace se obtiene el siguiente error 'Public Sub New (colección AsIEnumerable (De INota)) ': conversiones implícitas de' DataRowCollection 'a' IEnumerable (Of INote) '. – Coppermill

+5

No, él quiere decir lo que escribió. Eso hará que la lista se configure con el tamaño del conjunto de resultados. – Jake

-1

Si las propiedades de la lista coincide con los nombres de los campos en la tabla de datos debería poder crear algún tipo de rutina de reflexión genérica.

+0

Pero no es necesario crear un objeto nuevo, debe hacer referencia al objeto. – Coppermill

0

¿Desea hacer referencia a las filas de la tabla? En ese caso, debe usar la propiedad DataTable.Rows.

Prueba esto:

notes.AddRange(table.Rows); 

Si las filas de la tabla implementan INota entonces esto debería funcionar.

alternativa usted puede hacer como lo hizo anteriormente:

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

Esto está en table.Rows Advertencia errores de tiempo de ejecución puede ocurrir cuando la conversión de 'System.Data.DataRowCollection' a 'System.Collections.Generic.IList (Of.INote)' Esta es la generación de un nuevo objeto, que es lo que trato de evitar – Coppermill

+0

No, esto no debería crear objetos nuevos. Todo lo que estás haciendo es enviar el objeto a otro tipo. –

1

Por qué no pasar el DataTable en la función en lugar de crear instancias de ella? Eso simplemente contendría una referencia.

Esa es una respuesta demasiado simple que también valdrá la pena para ti Estoy seguro, pero no veo cómo no resuelve tu problema.

+0

yo después de un INota a ser devuelto – Coppermill

1

No estoy seguro si esto es lo que estás buscando, pero podrías intentar algo como esto.

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

Esto es lo que he hecho, así que espero que esto ayude. No estoy seguro de si es la manera correcta de hacerlo, pero funciona para lo que necesitábamos.

+0

Esto genera un nuevo objeto, necesito el código para hacer referencia al objeto Categoría cat = new Categoría(); Casi como tables.Rows Pero eso no funciona – Coppermill

+0

con que se pueden mapear los atributos que desea utilizar gato Categoría = (lista ). ese es un enfoque más grande, pero no está mal –

6

Tengo otro enfoque que podría valer la pena echarle un vistazo. Es un método de ayuda. Cree un archivo de clase personalizado denominado 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); 
    } 

Imagine que desea obtener una lista de clientes.Ahora vamos a tener la siguiente persona que llama:

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

los atributos que tiene en su DataTable debe coincidir con la clase de cliente (campos como nombre, dirección, teléfono).

Espero que ayude!

Para quienes están dispuestos a saber por qué utilizar las listas en lugar de tablas de datos: link text

La muestra completa:

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

+1

stackoverflow solo me permite darte un punto, 2 ++ –

+0

¿se puede hacer esta conversión con un lector de datos? –

+0

¡Estaba vagando si es posible evitar que este "debe coincidir" con los atributos de clase y los campos de tablas de datos! –