web-dev-qa-db-ja.com

List <T>をDataSetに変換するにはどうすればよいですか?

オブジェクトのリストが与えられた場合、リスト内の各アイテムが行で表され、各プロパティが行内の列であるデータセットに変換する必要があります。次に、このDataSetは、Excelドキュメントをレポートとして作成するために、 Aspose.Cells 関数に渡されます。

私が持っているとしましょう:

public class Record
{
   public int ID { get; set; }
   public bool Status { get; set; }
   public string Message { get; set; }
}

リストレコードが与えられた場合、次のようにそれをデータセットに変換するにはどうすればよいですか?

ID Status Message
1  true   "message" 
2  false  "message2" 
3  true   "message3" 
...

現時点で私が考えることができるのは次のとおりです。

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

しかし、この方法では、少なくとも新しいプロパティがRecordに追加された場合、それらはDataSetに表示されないため、より良い方法があるはずだと思います...しかし同時に、それぞれの順序を制御できますプロパティが行に追加されます。

誰かがこれを行うためのより良い方法を知っていますか?

15
mezoid

基になる型のプロパティを調べて、リフレクションとジェネリックを介してそれを行うことができます。

私が使用するこの拡張メソッドを検討してください。

    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;
    }
31
CMS

このコードはMicrosoftフォーラムで見つけました。これは、これまでのところ最も簡単な方法の1つであり、理解と使用が簡単です。これで時間を節約できました。実際の実装に変更を加えることなく、これを拡張メソッドとしてカスタマイズしました。以下はコードです。それは多くの説明を必要としません。

同じ実装で2つの関数シグネチャを使用できます

1)public static DataSet ToDataSetFromObject(this object dsCollection)

2)public static DataSet ToDataSetFromArrayOfObject(this object [] arrCollection)。以下の例ではこれを使用します。

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

この拡張機能をコードで使用するには

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

さらにReflectionを使用してクラスRecordのプロパティを決定し、新しいプロパティの追加を処理することを除けば、それだけです。

1
Mitch Wheat

Listにプリミティブ要素またはString要素が含まれている場合を処理するために、CMSの拡張メソッドにいくつかの変更を加えました。その場合、結果のDataTableには、リスト内の値ごとにColumnを持つ1つのRowのみが含まれます。

最初は、すべての値型(プリミティブ型だけでなく)を含めることを考えましたが、構造(値型)を含めたくありませんでした。

この変更は、List(Of Long)またはList<long>DataTableに変換して、MS SQL2008ストアドプロシージャでテーブル値パラメーターとして使用する必要があることから生じました。

申し訳ありませんが、私のコードはVBこの質問にタグが付けられていますが c# ;私のプロジェクトはVB(選択)そしてc#の変更を適用するのは難しいことではありません。

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
0
Tlatoani

私はこのタスクを実行するために自分で小さなライブラリを作成しました。オブジェクトタイプがデータテーブルに変換されるのは初めてです。オブジェクトタイプを変換するすべての作業を実行するメソッドを発行します。

その燃えるような速い。ここで見つけることができます: GoogleCodeのModelShredder

0