Wie verwandeln wir eine Liste in ein DataSet?
-
22-08-2019 - |
Frage
eine Liste von Objekten gegeben, Ich brauche den es in einen Datensatz zu transformieren, wobei jedes Element in der Liste durch eine Zeile dargestellt wird und jede Eigenschaft ist eine Spalte in der Zeile. Dieser Datensatz wird dann in eine Aspose.Cells Funktion, um ein Excel-Dokument als ein Bericht zu erstellen.
Sagen wir, ich habe folgendes:
public class Record
{
public int ID { get; set; }
public bool Status { get; set; }
public string Message { get; set; }
}
Eine Liste Aufzeichnungen gegeben, wie kann ich es in ein DataSet-Transformation wie folgt:
ID Status Message
1 true "message"
2 false "message2"
3 true "message3"
...
Im Moment ist das einzige, was ich denken kann, ist wie folgt:
DataSet ds = new DataSet
ds.Tables.Add();
ds.Tables[0].Add("ID", typeof(int));
ds.Tables[0].Add("Status", typeof(bool));
ds.Tables[0].Add("Message", typeof(string));
foreach(Record record in records)
{
ds.Tables[0].Rows.Add(record.ID, record.Status, record.Message);
}
Aber diese Art und Weise läßt ich denken, es muss ein besserer Weg sein, da zumindest, wenn neue Eigenschaften zu Datensatz hinzugefügt werden, dann werden sie nicht in der DataSet zeigen ... aber zugleich erlaubt es, mir zu kontrollieren die Reihenfolge jede Eigenschaft wird auf die Zeile hinzugefügt.
Kennt jemand einen besseren Weg, dies zu tun?
Lösung
Sie können es durch Reflexion und Generika tun, um die Eigenschaften des zugrunde liegenden Typs Inspektion.
Betrachten Sie diese Erweiterung Methode, die ich benutze:
public static DataTable ToDataTable<T>(this IEnumerable<T> collection)
{
DataTable dt = new DataTable("DataTable");
Type t = typeof(T);
PropertyInfo[] pia = t.GetProperties();
//Inspect the properties and create the columns in the DataTable
foreach (PropertyInfo pi in pia)
{
Type ColumnType = pi.PropertyType;
if ((ColumnType.IsGenericType))
{
ColumnType = ColumnType.GetGenericArguments()[0];
}
dt.Columns.Add(pi.Name, ColumnType);
}
//Populate the data table
foreach (T item in collection)
{
DataRow dr = dt.NewRow();
dr.BeginEdit();
foreach (PropertyInfo pi in pia)
{
if (pi.GetValue(item, null) != null)
{
dr[pi.Name] = pi.GetValue(item, null);
}
}
dr.EndEdit();
dt.Rows.Add(dr);
}
return dt;
}
Andere Tipps
Neben zusätzlich Reflection
mit den Eigenschaften der Klasse Record
um zu bestimmen, kümmern neue Eigenschaften hinzuzufügen, das ist ziemlich viel es.
Ich habe diesen Code auf Microsoft-Forum. Dies ist bisher eine der einfachste Weg, einfach zu verstehen und zu nutzen. Das hat mich Stunden gespeichert. Ich habe dies auf tatsächliche implementaion ohne Änderung als Erweiterungsmethode angepasst. Unten ist der Code. es erfordert nicht viel Erklärung.
Sie können zwei Funktionssignatur mit derselben Implementierung verwenden
1) public static DataSet ToDataSetFromObject (das Objekt dsCollection)
2) public static DataSet ToDataSetFromArrayOfObject (das Objekt [] arrCollection). Ich werde diese in folgendem Beispiel werden.
// <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;
}
Mit dieser Erweiterung nutzen zu können, in Code
Country[] objArrayCountry = null;
objArrayCountry = ....;// populate your array
if ((objArrayCountry != null)) {
dataset = objArrayCountry.ToDataSetFromArrayOfObject();
}
Ich habe eine kleine Bibliothek selbst geschrieben, um diese Aufgabe zu erfüllen. Es nutzt Reflexion nur zum ersten Mal ein Objekttyp auf eine Datentabelle übersetzt werden soll. Es gibt ein Verfahren, das die ganze Arbeit übersetzt einen Objekttyp tun wird.
Der blitzschnell. Sie können es hier finden: ModelShredder auf Google
Ich habe einige Änderungen an CMS-Extension-Methode den Fall zu behandeln, wenn die List
primitive oder String
Elemente enthält. In diesem Fall wird die resultierende DataTable
haben nur eine Column
mit einem Row
für jeden der Werte in der Liste.
Zuerst dachte ich, alle Werttypen einschließlich (nicht nur primitive Typen), aber ich wollte nicht Strukturen (die Werttypen sind) einbezogen werden.
Diese Änderung ergab sich aus meinem Bedürfnis eine List(Of Long)
der Umwandlung oder List<long>
in eine DataTable
es als Tabellenwertparameter in einer MS SQL 2008 für gespeicherte Prozeduren zu verwenden.
Es tut mir leid mein Code in VB ist, obwohl diese Frage c # ; mein Projekt ist in VB (nicht meine Wahl) und es sollte nicht schwer sein, die Änderungen in c # anzuwenden.
Imports System.Runtime.CompilerServices
Imports System.Reflection
Module Extensions
<Extension()>
Public Function ToDataTable(Of T)(ByVal collection As IEnumerable(Of T)) As DataTable
Dim dt As DataTable = New DataTable("DataTable")
Dim type As Type = GetType(T)
Dim pia() As PropertyInfo = type.GetProperties()
' For a collection of primitive types create a 1 column DataTable
If type.IsPrimitive OrElse type.Equals(GetType(String)) Then
dt.Columns.Add("Column", type)
Else
' Inspect the properties and create the column in the DataTable
For Each pi As PropertyInfo In pia
Dim ColumnType As Type = pi.PropertyType
If ColumnType.IsGenericType Then
ColumnType = ColumnType.GetGenericArguments()(0)
End If
dt.Columns.Add(pi.Name, ColumnType)
Next
End If
' Populate the data table
For Each item As T In collection
Dim dr As DataRow = dt.NewRow()
dr.BeginEdit()
' Set item as the value for the lone column on each row
If type.IsPrimitive OrElse type.Equals(GetType(String)) Then
dr("Column") = item
Else
For Each pi As PropertyInfo In pia
If pi.GetValue(item, Nothing) <> Nothing Then
dr(pi.Name) = pi.GetValue(item, Nothing)
End If
Next
End If
dr.EndEdit()
dt.Rows.Add(dr)
Next
Return dt
End Function
End Module