Как мне преобразовать Список <T>в DataSet? - PullRequest
14 голосов
/ 07 февраля 2009

Учитывая список объектов, мне нужно преобразовать его в набор данных, где каждый элемент в списке представлен строкой, а каждое свойство - столбцом в строке. Затем этот набор данных будет передан в функцию Aspose.Cells для создания документа Excel в виде отчета.

Скажи, что у меня есть следующее:

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

С учетом записей List, как мне преобразовать его в DataSet следующим образом:

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

Но этот путь заставляет меня думать, что должен быть лучший способ, поскольку, по крайней мере, если новые свойства будут добавлены в запись, они не будут отображаться в наборе данных ... но в то же время это позволяет мне порядок добавления каждого свойства в строку.

Кто-нибудь знает лучший способ сделать это?

Ответы [ 5 ]

29 голосов
/ 07 февраля 2009

Вы можете сделать это с помощью отражения и обобщений, проверяя свойства базового типа.

Рассмотрим метод расширения, который я использую:

    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;
    }
1 голос
/ 01 августа 2017

Я нашел этот код на форуме Microsoft. Это пока один из самых простых способов, который легко понять и использовать. Это сэкономило мне часы. Я настроил это как метод расширения без каких-либо изменений в фактической реализации. Ниже приведен код. это не требует особых объяснений.

Вы можете использовать две сигнатуры функции с одинаковой реализацией

1) public static DataSet ToDataSetFromObject (этот объект dsCollection)

2) открытый статический DataSet ToDataSetFromArrayOfObject (это объект [] 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 голос
/ 07 февраля 2009

Помимо дополнительного использования Reflection для определения свойств класса Record, чтобы позаботиться о добавлении новых свойств, вот и все.

0 голосов
/ 31 января 2013

Я внес некоторые изменения в метод расширения CMS для обработки случая, когда List содержит примитивные или String элементы. В этом случае результирующий DataTable будет иметь только один Column с Row для каждого из значений в списке.

Сначала я подумал о включении всех типов значений (не только примитивных типов), но я не хотел, чтобы структуры (которые являются типами значений) были включены.

Это изменение возникло из-за необходимости конвертировать List(Of Long) или List<long> в DataTable, чтобы использовать его в качестве табличного параметра в хранимой процедуре MS SQL 2008.

Извините, мой код в VB, хотя этот вопрос помечен ; мой проект в 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 голосов
/ 19 июня 2009

Я сам написал небольшую библиотеку для выполнения этой задачи. Он использует отражение только в первый раз, когда тип объекта должен быть переведен в таблицу данных. Он испускает метод, который выполняет всю работу по переводу типа объекта.

Пылающий быстро. Вы можете найти его здесь: ModelShredder на GoogleCode

...