如何将 LINQ ToList() 函数转换为数据表 c#

How to convert LINQ ToList() function to datatable c#

这就是我的 xml 的样子

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <orders>
    <OrderID>10248</OrderID>
    <CustomerID>VINET</CustomerID>
    <EmployeeID>5</EmployeeID>
    <OrderDate>1996-07-04T00:00:00</OrderDate>
    <RequiredDate>1996-08-01T00:00:00</RequiredDate>
    <ShippedDate>1996-07-16T00:00:00</ShippedDate>
    <ShipVia>3</ShipVia>
    <Freight>32.3800</Freight>
    <ShipName>Vins et alcools Chevalier</ShipName>
    <ShipAddress>59 rue de l'Abbaye</ShipAddress>
    <ShipCity>Reims</ShipCity>
    <ShipPostalCode>51100</ShipPostalCode>
    <ShipCountry>France</ShipCountry>
  </orders>
</Root>

我用这种方式使用 LINQ 解析上面的 xml

document.Descendants("orders").Select(c => c).ToList()

我想以表格格式列出 xml 数据,就像 sql 查询 return 数据一样。 我搜索并得到 link link 建议使用我遵循的 CopyToDataTable() extension 方法,但我仍然没有得到表格格式的结果。

所以指导我如何转换我的 ToList() to Datatable 结果输出看起来像

OrderID      CustomerID      EmployeeID
-------      ----------      -----------
10248        VINET           5
10249        AJAY            11
11027        Smith           09

这是我从 MSDN 获得的 CopyToDataTable 的完整代码

public static class DataSetLinqOperators
{
    public static DataTable CopyToDataTable<T>(this IEnumerable<T> source)
    {
        return new ObjectShredder<T>().Shred(source, null, null);
    }

    public static DataTable CopyToDataTable<T>(this IEnumerable<T> source,
                                                DataTable table, LoadOption? options)
    {
        return new ObjectShredder<T>().Shred(source, table, options);
    }

}

public class ObjectShredder<T>
{
    private FieldInfo[] _fi;
    private PropertyInfo[] _pi;
    private Dictionary<string, int> _ordinalMap;
    private Type _type;

    public ObjectShredder()
    {
        _type = typeof(T);
        _fi = _type.GetFields();
        _pi = _type.GetProperties();
        _ordinalMap = new Dictionary<string, int>();
    }

    public DataTable Shred(IEnumerable<T> source, DataTable table, LoadOption? options)
    {
        if (typeof(T).IsPrimitive)
        {
            return ShredPrimitive(source, table, options);
        }


        if (table == null)
        {
            table = new DataTable(typeof(T).Name);
        }

        // now see if need to extend datatable base on the type T + build ordinal map
        table = ExtendTable(table, typeof(T));

        table.BeginLoadData();
        using (IEnumerator<T> e = source.GetEnumerator())
        {
            while (e.MoveNext())
            {
                if (options != null)
                {
                    table.LoadDataRow(ShredObject(table, e.Current), (LoadOption)options);
                }
                else
                {
                    table.LoadDataRow(ShredObject(table, e.Current), true);
                }
            }
        }
        table.EndLoadData();
        return table;
    }

    public DataTable ShredPrimitive(IEnumerable<T> source, DataTable table, LoadOption? options)
    {
        if (table == null)
        {
            table = new DataTable(typeof(T).Name);
        }

        if (!table.Columns.Contains("Value"))
        {
            table.Columns.Add("Value", typeof(T));
        }

        table.BeginLoadData();
        using (IEnumerator<T> e = source.GetEnumerator())
        {
            Object[] values = new object[table.Columns.Count];
            while (e.MoveNext())
            {
                values[table.Columns["Value"].Ordinal] = e.Current;

                if (options != null)
                {
                    table.LoadDataRow(values, (LoadOption)options);
                }
                else
                {
                    table.LoadDataRow(values, true);
                }
            }
        }
        table.EndLoadData();
        return table;
    }

    public DataTable ExtendTable(DataTable table, Type type)
    {
        // value is type derived from T, may need to extend table.
        foreach (FieldInfo f in type.GetFields())
        {
            if (!_ordinalMap.ContainsKey(f.Name))
            {
                DataColumn dc = table.Columns.Contains(f.Name) ? table.Columns[f.Name]
                    : table.Columns.Add(f.Name, f.FieldType);
                _ordinalMap.Add(f.Name, dc.Ordinal);
            }
        }
        foreach (PropertyInfo p in type.GetProperties())
        {
            if (!_ordinalMap.ContainsKey(p.Name))
            {
                DataColumn dc = table.Columns.Contains(p.Name) ? table.Columns[p.Name]
                    : table.Columns.Add(p.Name, p.PropertyType);
                _ordinalMap.Add(p.Name, dc.Ordinal);
            }
        }
        return table;
    }

    public object[] ShredObject(DataTable table, T instance)
    {

        FieldInfo[] fi = _fi;
        PropertyInfo[] pi = _pi;

        if (instance.GetType() != typeof(T))
        {
            ExtendTable(table, instance.GetType());
            fi = instance.GetType().GetFields();
            pi = instance.GetType().GetProperties();
        }

        Object[] values = new object[table.Columns.Count];
        foreach (FieldInfo f in fi)
        {
            values[_ordinalMap[f.Name]] = f.GetValue(instance);
        }

        foreach (PropertyInfo p in pi)
        {
            values[_ordinalMap[p.Name]] = p.GetValue(instance, null);
        }
        return values;
    }
}

然后以这种方式调用 DataTable dtt =document.Descendants("orders").Select(c => c).ToList().CopyToDataTable(); 但它没有按照我想要的输出方式工作。

使用readxml将xml转换为数据表。下面的腿,值是 IEnumerable

类型
      IEnumerable<XElement> values =
                    from el in root.Elements("orders")
                    select el;


     DataSet ds = new DataSet();

                ds.ReadXml(new StringReader(new XElement("Root", values).ToString()));

DataTable d = ds.Tables[0];

            dgv.DataSource = d;  // dgv is a Data Grid View

Microsoft 发布了一个示例 class,它运行起来非常可靠且快速(就 而言,速度与基于反射的解决方案一样快)。

它叫做 ObjectShredder,你可以从 msdn

中获取它

使用此 ExtensionMethod 效果最佳

public static class CustomLINQtoDataSetMethods
{
    public static DataTable CopyToDataTable<T>(this IEnumerable<T> source)
    {
        return new ObjectShredder<T>().Shred(source, null, null);
    }

    public static DataTable CopyToDataTable<T>(
        this IEnumerable<T> source, DataTable table, LoadOption? options)
    {
        return new ObjectShredder<T>().Shred(source, table, options);
    }

}

但是由于 document.Descendants("orders") returns XElement 类型没有有用的属性但有一些 XElements 我建议您改用匿名类型。

用法:

var query = from o in document.Descendants("orders")
            select new 
            { 
                OrderID = (int)o.Element("OrderID"),
                CustomerID = (string)o.Element("CustomerID"),
                EmployeeID = (int)o.Element("EmployeeID"),
            };

var table = query.ToDataTable();

我还不能添加评论,所以你可以在这里做什么

根据下面的回答thread

您需要参考 FastMember

public static DataTable ToDataTable<T>(this IEnumerable<T> data)
        {
            if (data == null)
                throw new ArgumentNullException("data");
            var table = new DataTable("sd");
            using (var reader = ObjectReader.Create(data))
            {
                table.Load(reader);
            }
            return table;
        }

如果您使用的是 DataContext (linq-to-sql)

        public static DataTable ToDataTable<T>(this IQueryable<T> query, DataContext context)
        {
            if (query == null)
            {
                throw new ArgumentNullException("query");
            }

            IDbCommand cmd = context.GetCommand(query.AsQueryable());
            SqlDataAdapter adapter = new SqlDataAdapter();
            adapter.SelectCommand = (SqlCommand)cmd;
            DataTable dt = new DataTable("sd");
            try
            {
                cmd.Connection.Open();
                adapter.FillSchema(dt, SchemaType.Source);
                adapter.Fill(dt);
            }
            finally
            {
                cmd.Connection.Close();
            }
            return dt;
        }

已更新

你可以使用下面的功能

public static DataTable ConvertToDataTable(IEnumerable<XElement> data)
    {       
        var table = new DataTable();
        // create the columns
        foreach(var xe in data.First().Descendants())
            table.Columns.Add(xe.Name.LocalName,typeof(string));
        // fill the data
        foreach(var item in data)
        {
            var row = table.NewRow();
            foreach(var xe in item.Descendants())
                row[xe.Name.LocalName] = xe.Value;
            table.Rows.Add(row);
        }
        return table;
    }

并使用函数

var table = ConvertToDataTable(document.Descendants("orders"));

在这里工作sample