2009-08-07 13 views
15

Ho un elenco di oggetti generico. Ogni oggetto ha 9 proprietà di stringa. Voglio trasformare quella lista in un set di dati che posso passare ad una vista datagrid ...... Qual'è il modo migliore per farlo?Converti elenco generico in serie di dati in C#

+1

possibile duplicato di [Come faccio a trasformare un elenco in un DataSet?] (Http://stackoverflow.com/questions/523153/how- do-i-transform-a-listt-in-a-dataset) –

risposta

12

Hai provato a legare direttamente la lista alla vista dati? Altrimenti, provalo prima perché ti farà risparmiare molto dolore. Se l'hai già provato, ti preghiamo di dirci cosa è andato storto, così potremo consigliarti meglio. L'associazione dati offre un comportamento diverso a seconda delle interfacce implementate dall'oggetto dati. Ad esempio, se il tuo oggetto dati implementa solo IEnumerable (ad esempio List), otterrai un binding unidirezionale di base, ma se implementa anche IBindingList (ad esempio BindingList, DataView), avrai un legame a due vie.

+0

binding direttamente non si risolve molto spesso: è lento e lo smistamento è un dolore. Se è solo fino a 1000 giri, per tutto il resto raccomando un traduttore veloce DataTable come il mio ModelShredder (vedi sotto) –

+1

L'ordinamento è un dolore. Quindi sta filtrando. Quindi è il montaggio. È possibile creare un oggetto che supporti tutti i casi d'uso del DataTable, ma non è una quantità insignificante di lavoro, specialmente se confrontato con la semplice copia dei dati su un DataTable. –

+0

sì, ecco perché ho scritto modelhredder. Ho paura che il montaggio non sia ovviamente supportato, ma non lo vedo come un problema perché penso che modificare i dati in una tabella dovrebbe essere evitato per i motivi sopra citati. C'è sempre Excel :-) –

0

Un'opzione consisterebbe nell'utilizzare un System.ComponenetModel.BindingList piuttosto che un elenco.

Ciò consente di utilizzarlo direttamente in un DataGridView. E a differenza di un normale System.Collections.Generic.List aggiorna DataGridView sulle modifiche.

2

codice di forza bruta per rispondere alla tua domanda:

DataTable dt = new DataTable(); 

//for each of your properties 
dt.Columns.Add("PropertyOne", typeof(string)); 

foreach(Entity entity in entities) 
{ 
    DataRow row = dt.NewRow(); 

    //foreach of your properties 
    row["PropertyOne"] = entity.PropertyOne; 

    dt.Rows.Add(row); 
} 

DataSet ds = new DataSet(); 
ds.Tables.Add(dt); 
return ds; 

Ora per la domanda effettiva. Perché vorresti farlo? Come accennato in precedenza, è possibile eseguire il binding direttamente a un elenco di oggetti. Forse uno strumento di segnalazione che prende solo i set di dati?

+0

Una risposta al motivo per cui si vuole fare questo, comunque, è la WCF. Ai servizi davvero non piace mettere i generici sul filo. Sto scrivendo del codice per restituire i risultati paginati e ordinati da un repository e sto affrontando un DataSet per ora ... Una ragione è che i campi che vengono restituiti non sono sempre gli stessi ... Io non sono sicuramente se volesse, potrebbe aver bisogno di DTO, il che significa che ho altri problemi, ma sto divagando :-) –

2

Ho scritto una piccola libreria per svolgere questo compito. Usa la riflessione solo per la prima volta che un tipo di oggetto deve essere tradotto in un datatable. Emette un metodo che farà tutto il lavoro traducendo un tipo di oggetto.

È la soluzione più veloce che conosca (ecco perché l'ho sviluppata :-)). Puoi trovarlo qui: ModelShredder su GoogleCode

Attualmente supporta solo la traduzione di un DataTable. Come hai formulato la tua domanda, questo dovrebbe essere sufficiente. Il supporto per i DataSet (si pensi a un semplice ORM inverso) è già stato sviluppato, verrà rilasciato in due punti deboli quando torno dalle vacanze :-)

4

È possibile creare un metodo di estensione per aggiungere tutti i valori delle proprietà tramite riflessione:

+0

Grazie per il codice, un piccolo problema però, i tipi Nullable stanno bombardando ... Proverò a modificarlo per accoglierli, ma non sono un professionista della riflessione. Se avrò capito qualcosa, posterò un aggiornamento :-) –

+0

Ok, ho dovuto fare due modifiche, una per i tipi Nullable e un'altra per i valori null ... t.Columns.Add (propInfo.Name, propInfo.PropertyType); diventa Tipo ColType = Nullable.GetUnderlyingType (propInfo.PropertyType) ?? propInfo.PropertyType; t.Columns.Add (propInfo.Name, ColType); e riga [propInfo.Name] = propInfo.GetValue (elemento, null); diventa riga [propInfo.Name] = propInfo.GetValue (elemento, null) ?? DBNull.Value; Grazie per il codice :-) –

11

C'è un bug con il codice di estensione di Lee sopra, è necessario aggiungere la riga appena riempita alla tabella t quando itera attraverso gli elementi nell'elenco.

public static DataSet ToDataSet<T>(this IList<T> list) { 

Type elementType = typeof(T); 
DataSet ds = new DataSet(); 
DataTable t = new DataTable(); 
ds.Tables.Add(t); 

//add a column to table for each public property on T 
foreach(var propInfo in elementType.GetProperties()) 
{ 
    t.Columns.Add(propInfo.Name, propInfo.PropertyType); 
} 

//go through each property on T and add each value to the table 
foreach(T item in list) 
{ 
    DataRow row = t.NewRow(); 
    foreach(var propInfo in elementType.GetProperties()) 
    { 
      row[propInfo.Name] = propInfo.GetValue(item, null); 
    } 

    //This line was missing: 
    t.Rows.Add(row); 
} 


return ds; 

}

55

Mi scuso per mettere una risposta fino a questa domanda, ma ho pensato che sarebbe stato il modo più semplice per osservare il mio codice finale. Esso include correzioni per i tipi nullable e valori nulli :-)

public static DataSet ToDataSet<T>(this IList<T> list) 
    { 
     Type elementType = typeof(T); 
     DataSet ds = new DataSet(); 
     DataTable t = new DataTable(); 
     ds.Tables.Add(t); 

     //add a column to table for each public property on T 
     foreach (var propInfo in elementType.GetProperties()) 
     { 
      Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType; 

      t.Columns.Add(propInfo.Name, ColType); 
     } 

     //go through each property on T and add each value to the table 
     foreach (T item in list) 
     { 
      DataRow row = t.NewRow(); 

      foreach (var propInfo in elementType.GetProperties()) 
      { 
       row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value; 
      } 

      t.Rows.Add(row); 
     } 

     return ds; 
    } 
+2

Grande! Questo mi ha appena salvato la vita in un progetto che sto facendo adesso! – Konamiman

+1

Mi hai appena salvato un sacco di tempo. Grazie – Willem

+2

Grazie per questo, ottimo frammento :) Solo un bugfix, ho aggiunto if (list.Count()!= 0) prima di foreach, perché, se la lista che non vuoi convertire è vuota, il codice genererà un'eccezione. –

1

ho leggermente modificato la risposta accettata gestendo i tipi di valore. Mi sono imbattuto in questo quando provo a fare quanto segue e perché GetProperties() è a lunghezza zero per i tipi di valore che stavo ottenendo un dataset vuoto.So che questo non è il caso d'uso per l'OP ma ho pensato di postare questa modifica nel caso in cui qualcun altro avesse trovato la stessa cosa.

Enumerable.Range(1, 10).ToList().ToDataSet(); 

public static DataSet ToDataSet<T>(this IList<T> list) 
{ 
    var elementType = typeof(T); 
    var ds = new DataSet(); 
    var t = new DataTable(); 
    ds.Tables.Add(t); 

    if (elementType.IsValueType) 
    { 
     var colType = Nullable.GetUnderlyingType(elementType) ?? elementType; 
     t.Columns.Add(elementType.Name, colType); 

    } else 
    { 
     //add a column to table for each public property on T 
     foreach (var propInfo in elementType.GetProperties()) 
     { 
      var colType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType; 
      t.Columns.Add(propInfo.Name, colType); 
     } 
    } 

    //go through each property on T and add each value to the table 
    foreach (var item in list) 
    { 
     var row = t.NewRow(); 

     if (elementType.IsValueType) 
     { 
      row[elementType.Name] = item; 
     } 
     else 
     { 
      foreach (var propInfo in elementType.GetProperties()) 
      { 
       row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value; 
      } 
     } 
     t.Rows.Add(row); 
    } 

    return ds; 
} 
0

ho trovato questo codice su Microsoft forum. Questo è finora uno dei modi più semplici, facili da capire e da usare. Questo mi ha risparmiato ore, l'ho personalizzato come metodo di estensione senza alcuna modifica al metodo effettivo. Di seguito è riportato il codice. non richiede molte spiegazioni

È possibile utilizzare due firma funzione con stessa implementazione

1) ToDataSetFromObject pubblico DataSet statico (questo oggetto dsCollection)

2) ToDataSetFromArrayOfObject DataSet public static (questo oggetto [] arrCollection). Ad esempio userò questo.

// <summary> 
// Serialize Object to XML and then read it into a DataSet: 
// </summary> 
// <param name="arrCollection">Array of object</param> 
// <returns>dataset</returns> 

public static DataSet ToDataSetFromArrayOfObject(this object[] arrCollection) 
{ 
    DataSet ds = new DataSet(); 
    try { 
     XmlSerializer serializer = new XmlSerializer(arrCollection.GetType); 
     System.IO.StringWriter sw = new System.IO.StringWriter(); 
     serializer.Serialize(sw, dsCollection); 
     System.IO.StringReader reader = new System.IO.StringReader(sw.ToString()); 
     ds.ReadXml(reader); 
    } catch (Exception ex) { 
     throw (new Exception("Error While Converting Array of Object to Dataset.")); 
    } 
    return ds; 
} 

Per utilizzare questa estensione nel codice

Country[] objArrayCountry = null; 
objArrayCountry = ....;// populate your array 
if ((objArrayCountry != null)) { 
    dataset = objArrayCountry.ToDataSetFromArrayOfObject(); 
}