2009-09-14 95 views
8

我在IQueryable(例如)上有C#扩展方法。 FindNewCustomers()FindCustomersRegisteredAfter(int year)等等,我用它们将LINQ to SQL“查询”链接在一起。LINQ-to-SQL编译查询问题(作为未编译查询)

现在我的问题:我想创建编译查询,例如:

private static Func<MyDataContext, SearchInfo, IQueryable<Customer>> 
     CQFindAll = 
      CompiledQuery.Compile((MyDataContext dc, SearchInfo info) => 
       dc.Contacts.Select(c => c).FindCustomersRegisteredAfter(info.RegYear) 
          .OrderBy(info.OrderInfo) 
          .Skip(info.SkipCount) 
          .Take(info.PageSize)); 

FindCustomersRegisteredAfter(int year)方法是扩展方法采取IQueryable和返回相同。 OrderBy方法也是一种扩展方法(System.Linq.Dynamic),它根据字符串创建一个动态表达式(例如,“FirstName ASC”将按升序排列字段FirstName)。 SkipTake是内置方法。

以上(不是编译查询,而是定期查询)工程完美。有一次,我把它放在一个编译的查询,我打了以下错误:

Method 'System.Linq.IQueryable`1[Domain.Customer] FindCustomersRegisteredAfter[Customer](System.Linq.IQueryable`1[Domain.Customer], Int32)' has no supported translation to SQL.

再次,这个完美的作品如果查询非编,只是一个普通的LINQ查询。该错误只出现在CompiledQuery.Compile()中时才会出现。

帮助??!

编辑:如果我创建通过VAR查询查询=(...)同样的方式CompiledQuery.Compile内,这是SQL生成:

SELECT [t1].[Id], [t1].[FirstName], [t1].[LastName], 
     [t1].[RegYear], [t1].[DeletedOn] 
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[LastName]) AS [ROW_NUMBER], 
     [t0].[Id], [t0].[FirstName], [t0].[LastName], [t0].[RegYear], 
     [t0].[DeletedOn] 
FROM [dbo].[Contacts] AS [t0] 
WHERE ([t0].[RegYear] > @p0) AND ([t0].[DeletedOn] IS NULL) 
    ) AS [t1] 
WHERE [t1].[ROW_NUMBER] BETWEEN @p1 + 1 AND @p1 + @p2 
ORDER BY [t1].[ROW_NUMBER] 

所以你看到, SQL是完全可翻译的,所以我只需要填写@ p0,@ p1和@ p2就可以重复使用! CompiledQuery.Compile有什么问题?!?

更新:我知道OrderBy不能工作(因为它不是@p参数)。我仍然想弄清楚为什么CompiledQuery.Compile不适用于我的扩展方法。互联网上的信息几乎不存在。

+5

我不明白为什么这是社区wiki。 – JustLoren 2009-11-05 18:17:32

回答

3

我相信编译后的查询必须可以转换成SQL,而你的扩展方法不能。如果您对由“常规”查询创建的SQL进行概要分析,您可能会发现它选择了整个表格,因此它可以将所有行提供给您的扩展方法。

你最好把你的过滤逻辑放在查询中(作为表达树的一部分),这样它可以被转换为SQL并运行服务器端。

OrderBy也是一个问题,因为跳过。你需要使这个可转换为SQL或LINQ将不得不返回所有的行,以便在客户端过滤它们。

如果您不能将它们表示为LINQ表达式,请考虑在服务器上创建SQL函数并将它们映射到您的DataContext。 LINQ将能够将这些转换为T-SQL函数调用。

编辑:

我想我假设你的扩展方法不是建立表达式树。抱歉。

考虑这个link这似乎与您的问题类似。它引用了另一个更详细的link

它看起来像MethodCallExpression是问题。

The code is a bit long to be posted here, but similar to tomasp.net's expander, I visit every expression in the expression tree and if the node is a MethodCallExpression which calls a method that returns an expression tree, I replace that MethodCallExpression by the expression tree returned by invoking the method.

因此,它出现的问题是,编译查询时,不执行该方法,所以没有表达式树翻译成SQL。

+0

当我创建一个中断点时,我可以看到SQL可以很容易地完全生成(包括skip,take,orderby等),只要它不是编译查询。 – Alex 2009-09-14 18:41:42

+0

我编辑帖子以显示生成的SQL。 – Alex 2009-09-14 19:08:53