使用DataContext从LINQ查询填充DataTable的最快方法

Jum*_*zza 7 c# linq asp.net datatable ienumerable

我正在尝试运行linq查询,但我需要将结果作为数据表,因为我使用它来存储来自同一viewstate对象中的不同查询的记录.

下面的两个版本编译,但返回一个空集.确切的错误是"值不能为空.参数名称:源".(是的,我检查过有数据):

MyDatabaseDataContext db = new MyDatabaseDataContext(conn); 
IEnumerable<DataRow> queryProjects = 
    (from DataRow p in db.STREAM_PROJECTs.AsEnumerable()
    where p.Field<int>("STREAM_ID") == StreamID
    select new
    {
        PROJECT_ID = p.Field<int>("PROJECT_ID"),
        PROJECT_NAME = p.Field<string>("PROJECT_NAME")
    }) as IEnumerable<DataRow>;
DataTable results = queryProjects.CopyToDataTable<DataRow>();
Run Code Online (Sandbox Code Playgroud)

...

//(from p in db.STREAM_PROJECTs.AsEnumerable()
//where p.STREAM_ID == StreamID
//select new
//{
//    p.PROJECT_NAME,
//    p.PROJECT_ID
//}) as IEnumerable<DataRow>;
Run Code Online (Sandbox Code Playgroud)

线程中的示例似乎也不适用于此情况.

我想我可以用老式的方式运行一个sql查询命令,但不是linq应该更快吗?

Ada*_*son 19

你的问题是这样的:

as IEnumerable<DataRow>
Run Code Online (Sandbox Code Playgroud)

as关键字执行安全转换,而不是转换,您似乎可能认为它正在进行转换.该as关键字是语义相同,这样做:

IEnumerable<DataRow> queryProjects = 
    (IEnumerable<DataRow>)(from DataRow p in db.STREAM_PROJECTs.AsEnumerable()
    where p.Field<int>("STREAM_ID") == StreamID
    select new
    {
        PROJECT_ID = p.Field<int>("PROJECT_ID"),
        PROJECT_NAME = p.Field<int>("PROJECT_NAME")
    });
Run Code Online (Sandbox Code Playgroud)

除版本as时,它不能投你的查询对象(这是一个不会抛出异常IQueryable<T>,这里T是一个匿名类型)到IEnumerable<DataRow>(它不是).

不幸的是,我没有内置的方法,它将采用一个具体的类型(如本例中的匿名类型),并将其转换为DataTable.编写一个不会太复杂,因为您基本上需要反射性地获取属性然后遍历集合并使用这些属性来创建列中的列DataTable.我将在一些例子中发表一个例子.

像这样的东西放在一个名字空间中的静态类中,你using应该提供一个可以做你想要的扩展方法:

public static DataTable ToDataTable<T>(this IEnumerable<T> source)
{
    PropertyInfo[] properties = typeof(T).GetProperties();

    DataTable output = new DataTable();

    foreach(var prop in properties)
    {
        output.Columns.Add(prop.Name, prop.PropertyType);
    }

    foreach(var item in source)
    {
        DataRow row = output.NewRow();

        foreach(var prop in properties)
        {
            row[prop.Name] = prop.GetValue(item, null);
        }

        output.Rows.Add(row);
    }

    return output;
}
Run Code Online (Sandbox Code Playgroud)