2009-08-07 15 views
15

Mam ogólną listę obiektów. Każdy obiekt ma 9 właściwości łańcuchowych. Chcę przekształcić tę listę w zestaw danych, który można przekazać do datagridview ...... Jak najlepiej to zrobić?Konwertuj listę ogólną na zbiór danych w C#

+1

możliwe duplikat [W jaki sposób przekształcać listy do DataSet?] (Http://stackoverflow.com/questions/523153/how- do-i-transform-a-listt-into-a-dataset) –

Odpowiedz

12

Czy próbowałeś powiązać listę bezpośrednio z datagridview? Jeśli nie, spróbuj najpierw, ponieważ pozwoli Ci to zaoszczędzić wiele bólu. Jeśli już próbowałeś, powiedz nam, co poszło nie tak, abyśmy mogli lepiej Ci doradzić. Powiązanie danych zapewnia inne zachowanie w zależności od tego, jakie interfejsy implementują obiekty obiektów danych. Na przykład, jeśli obiekt danych implementuje tylko IEnumerable (np. List), otrzymasz bardzo proste wiązanie jednokierunkowe, ale jeśli implementuje on także IBindingList (na przykład BindingList, DataView), uzyskuje się wiązanie dwukierunkowe.

+0

Oprawa bezpośrednio nie będzie działać zbyt często: jest powolna, a sortowanie to ból. Jeśli jest to zaledwie 1000 razy, to dobrze, na wszystko polecam szybki translator danych, taki jak mój ModelShredder (patrz poniżej). –

+1

Sortowanie to ból. Więc filtruje. Tak więc jest edycja. Możliwe jest zbudowanie obiektu obsługującego wszystkie przypadki użycia, które wykonuje DataTable, ale to nie jest trywialna praca - szczególnie w porównaniu z kopiowaniem danych do DataTable. –

+0

tak, dlatego napisałem modelshredder. Obawiam się, że edycja nie jest oczywiście obsługiwana, ale nie widzę w tym problemu, ponieważ uważam, że należy unikać edytowania danych w tabeli z wyżej wymienionych powodów. Zawsze jest excel :-) –

0

Jedną opcją byłoby użycie System.ComponenetModel.BindingList zamiast listy.

Umożliwia to korzystanie z niego bezpośrednio w DataGridView. I w przeciwieństwie do normalnego System.Collections.Generic.List aktualizuje DataGridView na zmiany.

2

brute force kod aby odpowiedzieć na pytanie:

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; 

teraz za rzeczywistą pytanie. Dlaczego chcesz to zrobić? Jak wspomniano wcześniej, możesz wiązać bezpośrednio do listy obiektów. Może narzędzie do raportowania, które pobiera tylko zbiory danych?

+0

Odpowiedź na pytanie, dlaczego ktoś chce to zrobić, tak czy inaczej, to WCF. Usługi naprawdę nie lubią umieszczać generycznych na drucie. Piszę kod do powracania stronicowanych i uporządkowanych wyników z repozytorium i na razie radzę sobie z DataSet ... Jednym z powodów jest to, że zwracane pola nie zawsze są takie same ... Nie jestem pewnie jeśli to poleci, może potrzebować DTO, co oznacza, że ​​mam inne problemy, ale dygresja :-) –

2

Sam napisałem małą bibliotekę, aby wykonać to zadanie. Używa refleksji tylko wtedy, gdy typ obiektu ma zostać przetłumaczony na datatable. Emituje metodę, która wykona całą pracę tłumacząc typ obiektu.

Jest to najszybsze rozwiązanie, jakie znam (dlatego go opracowałem :-)). Można go znaleźć tutaj: ModelShredder na kodzie Google

Obecnie obsługuje tylko tłumaczenie na DataTable. Jak sformułowałeś swoje pytanie, powinno to wystarczyć. Wsparcie dla DataSets (myśl o prostym odwróceniu ORM) jest już opracowane, zostanie wydane w dwóch słabych punktach, gdy wrócę z wakacji :-)

4

Można utworzyć metodę rozszerzenia, aby dodać wszystkie wartości właściwości poprzez odbicie:

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

    return ds; 
} 
+0

Dzięki za kod, jeden mały problem, typy Nullable bombardują ... Mam zamiar spróbować zmodyfikuj go, aby je pomieścić, ale nie jestem pro odbicia. Jeśli coś zadziała, opublikuję aktualizację :-) –

+0

Ok, musiałem wprowadzić dwie zmiany, jedną dla typów zerowych i inną dla wartości pustych ... t.Columns.Add (propInfo.Name, propInfo.PropertyType); staje się Typ ColType = Nullable.GetUnderlyingType (propInfo.PropertyType)? propInfo.PropertyType; t.Columns.Add (propInfo.Name, ColType); i wiersz [propInfo.Name] = propInfo.GetValue (item, null); staje się wiersz [propInfo.Name] = propInfo.GetValue (element, null) ?? DBNull.Value; Dzięki za kod :-) –

11

Występuje błąd z powyższym kodem rozszerzenia Lee, musisz dodać nowo wypełniony wiersz do tabeli t podczas powtarzania elementów na liście.

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

Przepraszam za wprowadzenie w górę odpowiedź na to pytanie, ale pomyślałem, że byłoby najprostszym sposobem, aby zobaczyć mój ostateczny kod. Obejmuje poprawki dla typów zerowych i wartości pustych :-)

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

Świetnie! To właśnie uratowało mi życie w projekcie, który teraz robię! – Konamiman

+1

Właśnie uratowałem mi dużo czasu. Dzięki – Willem

+2

Dziękuję za to, wspaniały fragment :) Tylko jeden błąd, dodałem, jeśli (list.Count()!= 0) przed foreach, ponieważ jeśli lista, którą chcesz przekonwertować, jest pusta, kod rzuci wyjątek. –

1

Ja nieznacznie zmodyfikowałem zaakceptowaną odpowiedź, posługując się typami wartości. Natknąłem się na to, próbując wykonać następujące czynności, a ponieważ GetProperties() ma zerową długość dla typów wartości, otrzymywałem pusty zestaw danych.Wiem, że to nie jest przypadek użycia dla OP, ale myślałem, że opublikuję tę zmianę na wypadek, gdyby ktoś inny natknął się na to samo.

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

znalazłem ten kod na Microsoft forum. Jest to jak dotąd jedna z najprostszych metod, łatwa do zrozumienia i zastosowania. To zaoszczędziło mi wiele godzin, dostosowałem ją jako metodę rozszerzenia bez żadnych zmian w aktualnej metodzie. Poniżej znajduje się kod. nie wymaga wiele wyjaśnień.

można korzystać z dwóch funkcji z podpisem samego wdrożenia

1) public static DataSet ToDataSetFromObject (ten obiekt dsCollection)

2) public static ToDataSetFromArrayOfObject DataSet (to obiekt [] arrCollection). Będę używał tego na przykład.

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

Aby używać tego rozszerzenia w kodzie

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