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?

14
demandé sur mezoid 2009-02-07 07:48:54

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;
    }
27
répondu CMS 2009-02-07 04:58:23

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.

1
répondu Mitch Wheat 2009-02-07 04:54:07

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

0
répondu Johannes Rudolph 2009-06-18 21:21:20

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 ; 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
0
répondu Tlatoani 2013-01-31 02:57:33

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();
}
0
répondu kumar chandraketu 2017-08-01 16:58:12