Comment transformer une liste en un ensemble de données?
avec une liste d'objets, je dois la transformer en un ensemble de données où chaque élément de la liste est représenté par une ligne et chaque propriété est une colonne dans la ligne. Cet ensemble de données sera ensuite passé à un Aspose.Les cellules fonction permettant de créer un document Excel en tant que rapport.
Dire que j'ai le code suivant:
public class Record
{
public int ID { get; set; }
public bool Status { get; set; }
public string Message { get; set; }
}
étant donné une liste d'enregistrements, comment la transformer en un ensemble de données comme suit:
ID Status Message
1 true "message"
2 false "message2"
3 true "message3"
...
à l'heure actuelle, la seule chose que je pouvez penser est comme suit:
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);
}
mais cette façon me laisse penser qu'il doit y avoir une meilleure façon puisque au moins si de nouvelles propriétés sont ajoutées pour enregistrer alors elles ne seront pas présentées dans l'ensemble de données...mais en même temps cela me permet de contrôler l'ordre de chaque propriété est ajoutée à la ligne.
personne Ne sait d'une meilleure façon de le faire?
5 réponses
Vous pouvez le faire par réflexion et génériques, en inspectant les propriétés du type sous-jacent.
Envisager cette extension de la méthode que j'utilise:
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;
}
mis à part le fait d'utiliser en plus Reflection
pour déterminer les propriétés de la classe Record
pour prendre soin de l'ajout de nouvelles propriétés, c'est assez bien.
j'ai moi-même écrit une petite bibliothèque pour accomplir cette tâche. Il utilise la réflexion seulement pour la première fois un type d'objet doit être traduit en un datatable. Il émet une méthode qui va faire tout le travail de traduction d'un type d'objet.
son embrasement rapide. Vous pouvez le trouver ici: ModelShredder on GoogleCode
j'ai fait quelques changements à la méthode d'extension de CMS pour gérer le cas quand le List
contient primitif ou String
éléments. Dans ce cas, la résultante DataTable
n'ont qu'un seul Column
avec un Row
pour chacune des valeurs dans la liste.
au début j'ai pensé à inclure tous les types de valeurs (pas seulement les types primitifs) mais je ne voulais pas que les Structures (qui sont des types de valeurs) soient incluses.
ce changement est né de mon besoin de convertir un List(Of Long)
, ou List<long>
, dans un DataTable
pour l'utiliser comme paramètre de valeur de Table dans une procédure MS SQL 2008 stockée.
je suis désolé mon code est en VB même si cette question est marquée c#; mon projet est en VB (pas mon choix) et il ne devrait pas être difficile d'appliquer les changements en 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
j'ai trouvé ce code sur Microsoft forum. C'est de loin l'un de simple, facile à comprendre et à utiliser. Cela m'a évité des heures. J'ai personnalisé ceci comme méthode d'extension sans aucun changement à la mise en œuvre réelle. Ci-dessous est le code. il ne nécessite pas beaucoup d'explication.
vous pouvez utiliser deux signatures de fonction avec la même implémentation
1) public static data set ToDataSetFromObject(this objet dsCollection)
2) public static Data set Tod Atasetfromarrayofobject( this object [] arrCollection). Je vais utiliser celui-ci dans l'exemple ci-dessous.
// <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;
}
Pour utiliser cette extension dans le code
Country[] objArrayCountry = null;
objArrayCountry = ....;// populate your array
if ((objArrayCountry != null)) {
dataset = objArrayCountry.ToDataSetFromArrayOfObject();
}