把Linq查询返回的var类型的数据 转换为DataTable

Posted 邢帅杰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了把Linq查询返回的var类型的数据 转换为DataTable相关的知识,希望对你有一定的参考价值。

问题:我要获得一个角色下对应的所有用户,需要两表连接查询,虽然返回的只有用户数据,但是我想到若是返回的不只是用户数据,而还要加上角色信息,那么我返回什么类型呢,返回var吗,这样不行。

于是我网上找找是否能返回DataTable呢,这样我不用创建中间类了。然后就找到下面的代码:这是别人写的,高手。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Common
{
    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;
        }
    }
}

来源:http://www.cnblogs.com/jaxu/archive/2011/08/02/2125055.html

Jaxu的博客写挺好的,都可以看看。

不过我最后没有用这个方法,我新建了一个中间类,来形成List返回:

/// <summary>
        /// 根据RoleID获得该角色下的用户成员
        /// </summary>
        /// <param name="rid"></param>
        /// <returns></returns>
        public List<S_ROLE_USER_Query_Dto> GetRoleUser(int rid, string name)
        {
            IQueryable<S_ROLE_USER_Query_Dto> result = from ru in this.Context.Set<Domain.S_ROLE_USER>()
                                                       join u in this.Context.Set<Domain.S_USER>()
                                              on new { ru.U_ID }
                                              equals new { u.U_ID }
                                                       where (ru.R_ID == rid && (string.IsNullOrEmpty(name) ? true : (u.U_NAME.Contains(name) || u.U_REALNAME.Contains(name))))
                                                       select new S_ROLE_USER_Query_Dto
                                                       {
                                                           U_ID = ru.U_ID,
                                                           U_NAME = u.U_NAME,
                                                           U_REALNAME = u.U_REALNAME,
                                                           U_EMAIL = u.U_EMAIL,
                                                           U_MOBILE = u.U_MOBILE,
                                                           U_TEL = u.U_TEL,
                                                           R_ID = ru.R_ID
                                                       };
            return result.ToList();
        }

  

以上是关于把Linq查询返回的var类型的数据 转换为DataTable的主要内容,如果未能解决你的问题,请参考以下文章

Linq标准查询操作符

在 LINQ 查询中将 KeyValuePair 转换为匿名类型

如何将 linq var 数据类型传递给方法? [复制]

利用linq to sql 建立查询方法返回值类型为List<T> 怎样去除集合中的重复数据?

将两个查询的左外连接转换为 LINQ

Net Core:在洋葱架构中使用OData,将查询参数转换为Linq