オブジェクトのリストが与えられた場合、リスト内の各アイテムが行で表され、各プロパティが行内の列であるデータセットに変換する必要があります。次に、この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に表示されないため、より良い方法があるはずだと思います...しかし同時に、それぞれの順序を制御できますプロパティが行に追加されます。
誰かがこれを行うためのより良い方法を知っていますか?
基になる型のプロパティを調べて、リフレクションとジェネリックを介してそれを行うことができます。
私が使用するこの拡張メソッドを検討してください。
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;
}
このコードは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();
}
さらにReflection
を使用してクラスRecord
のプロパティを決定し、新しいプロパティの追加を処理することを除けば、それだけです。
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
私はこのタスクを実行するために自分で小さなライブラリを作成しました。オブジェクトタイプがデータテーブルに変換されるのは初めてです。オブジェクトタイプを変換するすべての作業を実行するメソッドを発行します。
その燃えるような速い。ここで見つけることができます: GoogleCodeのModelShredder