Domanda

Ho un metodo di selezione del livello dati che restituisce un datatable. Viene chiamato da un metodo di livello aziendale che dovrebbe quindi restituire un elenco generico fortemente tipizzato.

Quello che voglio fare è molto simile (ma non uguale a) questa domanda:
Come si converte una DataTable in un elenco generico?

La cosa diversa è che voglio che l'elenco contenga oggetti fortemente tipizzati piuttosto che datarows (inoltre, non ho ancora disponibile linq qui).

Sono preoccupato per le prestazioni. A sua volta, il metodo del livello aziendale verrà chiamato dal livello presentazione e i risultati verranno ripetuti per la visualizzazione all'utente. Sembra molto dispendioso aggiungere un'ulteriore iterazione a livello aziendale, ripeterlo subito per la presentazione, quindi voglio che sia il più rapido possibile.

Questo è un compito comune, quindi sto davvero cercando un buon modello che possa essere ripetuto più volte.

È stato utile?

Soluzione

Conosci in anticipo la struttura di DataTable e l'oggetto digitato? È possibile utilizzare un delegato per eseguire il mapping. In caso contrario (ovvero, tutto ciò che sai è Type e proprietà), ci sono modi per accelerare l'accesso dinamico ai membri (come HyperDescriptor).

Ad ogni modo, considera un blocco iteratore; in questo modo non è necessario bufferizzare gli oggetti per la seconda volta; ovviamente, se hai a che fare solo con conteggi di riga piccoli non è un problema.

Puoi chiarire qualcuno di questi punti? Posso aggiungere molti più dettagli ...

In parole povere, cosa c'è di sbagliato in:

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

(i problemi di cui sopra potrebbero guidare l'approccio giusto ...)

Altri suggerimenti

Il problema con l'esempio sopra è che è terribilmente lento. Ho una DataTable con circa 400 righe e questa conversione richiede ben 5 o 6 secondi!

Sembra un compito abbastanza comune, quindi sono sorpreso di non vedere qualcuno qui con una soluzione più performante.

* Aggiorna !! * Solo per i calci, ho pensato di provare a convertire usando LINQ invece di iterare attraverso la DataTable e aggiungere alla mia lista. Quello che ho fatto è stato il seguente:

   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();

Il primo metodo (ripetendo ogni riga) ha impiegato 5,3 secondi e il metodo che utilizza LINQ ha impiegato 1,8 secondi!

Dovrai iterare attraverso i datarows e convertirli nei tuoi oggetti in qualche momento, ma potresti scrivere una collezione personalizzata con un costruttore che prende una collezione di datarows e che converte ogni articolo nel tuo tipo di oggetto quando richiesto invece di tutto in una volta.

Supponi di aver definito la tua raccolta personalizzata che implementa IList<T>. Potrebbe quindi avere due campi interni: un riferimento alla raccolta di datarows e un List<T>. Il <=> verrebbe inizializzato sulla lunghezza della raccolta di datarows ma con valori nulli.

Ora nell'indicizzatore è possibile verificare se <=> contiene un valore in quell'indice e, in caso contrario, è possibile creare l'oggetto usando qualsiasi mezzo sarebbe utile e memorizzarlo lì prima di restituirlo.

Ciò rinverebbe la creazione dei tuoi oggetti fino a quando non sono stati richiesti e tu crei solo gli oggetti che sono stati richiesti.

I tuoi oggetti probabilmente avrebbero bisogno di un costruttore che prende un DataRow o avresti bisogno di una sorta di factory per crearli, ma questo è un altro argomento.

Solo per fornire un po 'più di facilità d'uso alla risposta di Mark in una semplice app console:

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();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top