【问题标题】:Why write a custom LINQ provider?为什么要编写自定义 LINQ 提供程序?
【发布时间】:2010-12-10 16:26:28
【问题描述】:

与编写实现 IEnumerable 的简单类相比,编写自定义 LINQ 提供程序有什么好处?

例如这个quesiton 显示Linq2Excel:

var book = new ExcelQueryFactory(@"C:\Users.xls");
var administrators = from x in book.Worksheet<User>()
                     where x.Role == "Administrator"
                     select x;

但是,与 IEnumerable 的“幼稚”实现相比有什么好处?

【问题讨论】:

  • 不知道为什么 linq-to-excel 从 IQueryable 中获利,但在某些情况下它可以使代码更快。

标签: c# linq linq-to-sql ienumerable


【解决方案1】:

Linq 提供者的目的基本上是将 Linq 表达式树(在查询的幕后构建)“翻译”成数据源的本地查询语言。如果数据已经在内存中,则不需要 Linq 提供程序; Linq 2 对象很好。但是,如果您使用 Linq 与 DBMS 或云之类的外部数据存储进行通信,那绝对是必不可少的。

任何查询结构的基本前提是数据源的引擎应该做尽可能多的工作,并且只返回客户端需要的数据。这是因为假设数据源最了解如何管理其存储的数据,并且因为数据的网络传输在时间上相对昂贵,因此应尽量减少。现在,实际上,第二部分是“仅返回客户要求的数据”;服务器无法读取您的程序的想法并知道它真正需要什么;它只能提供它所要求的。这里是一个智能 Linq 提供者绝对吹走“幼稚”实现的地方。使用生成表达式树的 Linq 的 IQueryable 端,Linq 提供程序可以将表达式树转换为 SQL 语句,DBMS 将使用该 SQL 语句返回客户端在 Linq 语句中请求的记录。一个简单的实现需要使用一些广泛的 SQL 语句检索所有记录,以便向客户端提供内存中对象的列表,然后由客户端完成过滤、分组、排序等所有工作。

例如,假设您使用 Linq 通过主键从数据库中的表中获取记录。 Linq 提供程序可以将dataSource.Query&lt;MyObject&gt;().Where(x=&gt;x.Id == 1234).FirstOrDefault() 转换为“SELECT TOP 1 * from MyObjectTable WHERE Id = 1234”。这将返回零或一条记录。 “天真的”实现可能会向服务器发送查询“SELECT * FROM MyObjectTable”,然后使用 Linq 的 IEnumerable 端(适用于内存类)进行过滤。在一个语句中,您希望从包含 1000 万条记录的表中生成 0-1 结果,您认为其中哪一个会更快地完成这项工作(甚至完全可以工作,而不会耗尽内存)?

【讨论】:

    【解决方案2】:

    如果您只想将 LINQ-to-Objects(即foreach-like)功能用于您的目的,则无需编写 LINQ 提供程序,该功能主要针对内存中的列表。

    确实如果您想分析查询的表达式树以便将其转换为其他内容(如 SQL),则需要编写 LINQ 提供程序。例如,您提到的 ExcelQueryFactory 似乎与 OLEDB-Connection 一起使用。这可能意味着它在查询数据时不需要将整个excel文件加载到内存中。

    【讨论】:

      【解决方案3】:

      一般性能。如果您有某种索引,则可以比简单的IEnumerable&lt;T&gt; 更快地进行查询。

      Linq-To-Sql 就是一个很好的例子。在这里,您将 linq 语句转换为 SQL 服务器可以理解的另一个语句。因此,服务器将使用索引进行过滤、排序……,而无需将整个表发送到客户端,然后客户端使用 linq-to-objects 进行处理。

      但在更简单的情况下它也很有用:

      如果您在属性 Time 上有一个树索引,那么像 .Where(x=&gt;(x.Time&gt;=now)&amp;&amp;(x.Time&lt;=tomorrow)) 这样的范围查询可以进行很多优化,并且不需要遍历可枚举中的每个项目。

      【讨论】:

        【解决方案4】:

        LINQ 将尽可能提供延迟执行以提高性能。

        IEnumurable 和 IQueryable 将完全提供不同的程序实现。 IQueryable 将通过动态构建表达式树来提供本地查询,这确实提供了比 IEnumurable 更好的性能。

        http://msdn.microsoft.com/en-us/vcsharp/ff963710.aspx

        如果我们不确定我们是否可以使用var 关键字,它会动态地初始化一个最合适的类型。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-01-24
          • 1970-01-01
          • 1970-01-01
          • 2010-10-11
          • 2011-06-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多