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?

War es hilfreich?

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 ; 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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top