Pregunta

Tengo un nivel de datos seleccione el método que devuelve un datatable.Se llama desde un método de nivel que debe devolver a continuación un establecimiento inflexible de tipos genéricos de la Lista.

Lo que quiero hacer es muy similar (pero no igual) a esta pregunta:
¿Cómo convertir un DataTable en una lista genérica?

Lo que es diferente es que quiero la lista de contener con establecimiento inflexible de tipos de objetos en lugar de datarows (también, no tengo linq disponible aquí).

Estoy preocupado por el rendimiento.El nivel de negocios método será llamado desde la capa de presentación, y los resultados se repetirá para mostrar al usuario.Parece un gran desperdicio para añadir un extra de iteración en el nivel de negocios, sólo lo hacen de nuevo de inmediato para la presentación, así que yo quiero que esto sea tan rápido como sea posible.

Esta es una tarea común, por lo que realmente estoy buscando un buen patrón que puede ser repetido una y otra vez.

¿Fue útil?

Solución

¿Conoce usted la estructura de la DataTable y el objeto introducido antes de tiempo?Usted podría utilizar un delegado para hacer el mapeo.Si no (es decir,todo lo que sabemos es una Type y propiedades) hay formas de acelerar la dinámica de acceso de los miembros (tales como HyperDescriptor).

De cualquier manera, considere la posibilidad de un iterador bloque;de esa manera usted no tiene que amortiguar los objetos de todo un segundo tiempo;por supuesto, si sólo se trata de pequeñas rowcounts esto no es un problema.

Puede usted aclarar alguno de estos puntos?Puedo añadir mucho más detalle...

En el más simple, lo que está mal con:

DataTable table = new DataTable {
    Columns = {
        {"Foo", typeof(int)},
        {"Bar", typeof(string)}
     }
};
for (int i = 0; i < 5000; i++) {
    table.Rows.Add(i, "Row " + i);
}

List<MyType> data = new List<MyType>(table.Rows.Count);
foreach (DataRow row in table.Rows) {
    data.Add(new MyType((int)row[0], (string)row[1]));
}

(los problemas que en la anterior podría dirigir el enfoque correcto...)

Otros consejos

El problema con el ejemplo anterior es que es terriblemente lento. ¡Tengo una DataTable con aproximadamente 400 filas y esta conversión lleva unos buenos 5 o 6 segundos!

Parece una tarea bastante común, así que me sorprende no ver a alguien aquí con una solución más eficaz.

* ¡Actualización! * Solo por diversión, pensé que intentaría convertir usando LINQ en lugar de iterar a través de DataTable y agregar a mi lista. Lo siguiente es lo que hice:

   List<MyObject> returnList = new List<MyObject>();

   MyDataTable dtMyData = new MyTableAdapter().GetMyData();

   returnLists = (from l in dtMyData
                 select new MyObject
                 {
                    Active = l.IsActive,
                    Email = l.Email,
                    //...
                    //About 40 more properties
                    //...
                    ZipCode = l.Zipcode
                  }).ToList();

¡El primer método (iterar a través de cada fila) tomó 5.3 segundos y el método que usa LINQ tomó 1.8 segundos!

Deberá iterar a través de los datarows y convertirlos en sus objetos en algún momento de todos modos, pero podría escribir una colección personalizada con un constructor que tome una colección de datarows y que convierta cada elemento en su tipo de objeto cuando se solicite. de todo a la vez.

Digamos que define su colección personalizada que implementa IList<T>. Entonces podría tener dos campos internos: una referencia a la colección de datarows y un List<T>. El <=> se inicializaría a la longitud de la colección de datarows pero con valores nulos.

Ahora en el indexador puede verificar si el <=> contiene un valor en ese índice y si no puede crear el objeto utilizando cualquier medio que sea útil y almacenarlo allí antes de devolverlo.

Esto pospondría la creación de sus objetos hasta que fueran solicitados y usted solo crearía los objetos que fueron solicitados.

Tus objetos probablemente necesitarían un constructor que tomara una DataRow o necesitarías algún tipo de fábrica para crearlos, pero ese es otro tema.

Solo para proporcionar un poco más de facilidad de uso a la respuesta de Mark en una aplicación de consola simple:

class Program
{
    static void Main(string[] args)
    {
        //define a DataTable obj
        DataTable table = new DataTable
        {
            Columns = {
            {"Foo", typeof(int)},
            {"Bar", typeof(string)}
         }
        };
        //populate it the DataTable 
        for (int i = 0; i < 3; i++)
        {
            table.Rows.Add(i, "Row " + i);
        }

        List<MyType> listWithTypedObjects= new List<MyType>(table.Rows.Count);
        foreach (DataRow row in table.Rows)
        {
            listWithTypedObjects.Add(new MyType((int)row[0], (string)row[1]));
        }

        Console.WriteLine(" PRINTING THE POPULATED LIST ");
        foreach (MyType objMyType in listWithTypedObjects)
        {
            Console.Write(" I have object of the type " + objMyType.ToString() + " => " );
            Console.Write(" with Prop1OfTypeInt " + objMyType.Prop1OfTypeInt.ToString() + " , ");
            Console.WriteLine(" with Prop1OfTypeInt " + objMyType.Prop2OfTypeString.ToString() + "  "); 
        }

        Console.WriteLine(" \n \n \n HIT A KEY TO EXIT THE PROGRAM ");
        Console.ReadKey();
    }
}

class MyType {

    public int Prop1OfTypeInt { get; set; }
    public string Prop2OfTypeString { get; set; } 

    /// <summary>
    /// Note the order of the passed parameters is important !!!
    /// </summary>
    public MyType( int prop1OfTypeInt , string prop2OfTypeString)
    {
        this.Prop1OfTypeInt = prop1OfTypeInt;
        this.Prop2OfTypeString = prop2OfTypeString; 

    }
}
public partial class issuereceive_manageroffice_bal
{
    public int issue_id{get;set;}
    public string process{get;set;}
    public DateTime issue_date{get;set;}
    public TimeSpan issue_time{get;set;}
    public string eg_no{get;set;}
    public string lotno{get;set;}
    public string clarity{get;set;}
    public string sieves{get;set;}
    public string shape{get;set;}
    public double issue_carat{get;set;}
    public int issue_pieces{get;set;}
    public int receive_pieces{get;set;}
    public double receive_carat{get;set;}
    public int kp_pieces{get;set;}
    public decimal kp_carat{get;set;}
    public double loss{get;set;}
    public string issue_manager{get;set;}
    public string issue_by{get;set;}
    public string receive_by{get;set;}
    public int status{get;set;}
    public DateTime receive_date{get;set;}
    public string receive_time{get;set;}
    public int factory_id{get;set;}

}


List<issuereceive_manageroffice_bal> issue_receive_list = new List<issuereceive_manageroffice_bal>();
issue_receive_list =
      (from DataRow dr in DataTable.Rows
      select new issuereceive_manageroffice_bal()
           {
               issue_id = 0,
               issue_time = TimeSpan.Parse("0"),
               receive_time = null,
               shape = null,
               process = dr["process"].ToString(),
               issue_date = Convert.ToDateTime(dr["issue_date"]),
               eg_no = dr["eg_no"].ToString(),
               lotno = dr["lotno"].ToString(),
               clarity = dr["clarity"].ToString(),
               sieves = dr["sieves"].ToString(),
               issue_carat = dr["issue_carat"].ToString() != "" ? double.Parse(dr["issue_carat"].ToString()) : 0,
               issue_pieces = dr["issue_pieces"].ToString() != "" ? int.Parse(dr["issue_pieces"].ToString()) : 0,
               receive_carat = dr["receive_carat"].ToString() != "" ? double.Parse(dr["receive_carat"].ToString()) : 0,
               kp_pieces = dr["kp_pieces"].ToString() != "" ? int.Parse(dr["kp_pieces"].ToString()) : 0,
               kp_carat = dr["kp_carat"].ToString() != "" ? decimal.Parse(dr["kp_carat"].ToString()) : 0,
               loss = dr["loss"].ToString() != "" ? double.Parse(dr["loss"].ToString()) : 0,
               issue_manager = dr["lotno"].ToString(),
               issue_by = dr["issue_by"].ToString(),
               receive_by = dr["receive_by"].ToString(),
               status = dr["status"].ToString() != "" ? int.Parse(dr["status"].ToString()) : 0,
               receive_date = Convert.ToDateTime(dr["receive_date"]),
               factory_id = dr["factory_id"].ToString() != "" ? int.Parse(dr["factory_id"].ToString()) : 0,

           }).ToList();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top