代码之家  ›  专栏  ›  技术社区  ›  mezoid

如何将List<T>转换为DataSet?

  •  17
  • mezoid  · 技术社区  · 16 年前

    给定一个对象列表,我需要将其转换为数据集,其中列表中的每个项目都由一行表示,每个属性都是行中的一列。然后,此DataSet将传递给 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);
    }
    

    但这种方式让我认为一定有更好的方法,因为至少如果将新属性添加到Record中,那么它们就不会出现在DataSet中。..但同时它允许我控制每个属性添加到行中的顺序。

    有人知道更好的方法吗?

    5 回复  |  直到 16 年前
        1
  •  32
  •   Christian C. Salvadó    16 年前

    您可以通过反射和泛型来检查底层类型的属性。

    考虑一下我使用的这个扩展方法:

        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;
        }
    
        2
  •  2
  •   kumar chandraketu    8 年前

    我在微软论坛上发现了这段代码。这是迄今为止最简单的方法之一,易于理解和使用。这为我节省了几个小时。我将其定制为扩展方法,而不对实际实现进行任何更改。下面是代码。这不需要太多解释。

    您可以使用具有相同实现的两个函数签名

    1) 公共静态数据集ToDataSetFromObject(此 对象 dsCollection)

    2) 公共静态数据集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();
    }
    
        3
  •  1
  •   Mitch Wheat    16 年前

    除了额外使用 Reflection 确定类的属性 Record 要添加新属性,就差不多了。

        4
  •  0
  •   Johannes Rudolph    16 年前

    我自己写了一个小图书馆来完成这项任务。它仅在对象类型首次转换为数据表时使用反射。它发出一个方法,该方法将完成翻译对象类型的所有工作。

    它燃烧得很快。你可以在这里找到它: ModelShredder on GoogleCode

        5
  •  0
  •   Tlatoani    12 年前

    我对CMS的扩展方法进行了一些更改,以处理以下情况 List 包含原始或 String 元素。在这种情况下,结果 DataTable 只会有一个 Column 用一个 Row 对于列表中的每个值。

    起初我想包括所有值类型(不仅仅是原始类型),但我不想包括结构(它们是值类型)。

    这一变化源于我需要转换一个 List(Of Long) ,或 List<long> ,变成a 数据表 将其用作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