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

Posted

技术标签:

【中文标题】使用 DataContext 从 LINQ 查询中填充 DataTable 的最快方法【英文标题】:Fastest way to fill DataTable from LINQ query using DataContext 【发布时间】:2011-02-10 04:00:04 【问题描述】:

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

下面的 2 个版本编译,但返回一个空集。确切的错误是 “值不能为空。 参数名称:来源”。(是的,我已经检查过有数据):

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

...

//(from p in db.STREAM_PROJECTs.AsEnumerable()
//where p.STREAM_ID == StreamID
//select new
//
//    p.PROJECT_NAME,
//    p.PROJECT_ID
//) as IEnumerable<DataRow>;

thread 中的示例似乎也不适用于这种情况。

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

【问题讨论】:

【参考方案1】:

你的问题是这样的:

as IEnumerable<DataRow>

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

除了带有as 的版本,当它无法将您的查询对象(这是一个IQueryable&lt;T&gt;,其中T 是一个匿名类型)转换为IEnumerable&lt;DataRow&gt;(它是't)。

不幸的是,我知道没有内置方法可以将具体类型的可枚举(如本例中的匿名类型)转换为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;

【讨论】:

我明白了 - 所以它只是隐藏了 invalidcastexception?那我怎么把它放到数据表中呢? @JumpingJezza:是的; as 用于您知道该对象实际上可能不是您期望的类型并且不是“异常”情况的情况。如果强制转换无效,as 关键字的计算结果为 null,并且(因此)只能与引用类型和 Nullable&lt;T&gt; 一起使用。请参阅我刚刚发布的编辑,了解可以将任何 IEnumerable&lt;T&gt; 转换为 DataTable 的示例扩展方法。 完美!另外我发现了一些关于as 的新东西:) 我必须内置检查 Nullable 类型,因为 output.Columns.Add 如果类型为空,则调用将失败

以上是关于使用 DataContext 从 LINQ 查询中填充 DataTable 的最快方法的主要内容,如果未能解决你的问题,请参考以下文章

SharePoint 服务器端对象模型 之 使用LINQ进行数据访问操作(Part 2)

SharePoint服务器端对象模型 之 使用LINQ进行数据访问操作(Part 4)

C#中LINQ怎么生成下面那条SQL

SharePoint服务器端对象模型 之 使用LINQ进行数据访问操作(Part 3)

在Linq-to-SQL中使用WHERE子句时出错

LINQ 基础语句