LINQ-to-SQL编译的查询问题(作为未编译的查询)

时间:2009-09-14 10:08:37

标签: c# linq linq-to-sql expression-trees compiled-query

我在IQueryable上有C#扩展方法,例如我使用FindNewCustomers()FindCustomersRegisteredAfter(int year)等来为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));

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方法也是一种扩展方法(System.Linq.Dynamic),它根据字符串创建动态表达式(例如“FirstName ASC”将对字段FirstName进行排序)。 OrderBySkip是内置方法。

以上(不是编译查询,而是常规查询)可以完美。一旦我把它放在编译的查询中,我就会遇到以下错误:

方法 'System.Linq.IQueryable`1 [Domain.Customer] FindCustomersRegisteredAfter [客户](System.Linq.IQueryable`1 [Domain.Customer],Int32)将' 没有支持转换为SQL。

再一次,如果查询是非编译的,这只是一个常规的L​​INQ查询。只有在CompiledQuery.Compile()内部才会出现错误。

帮助??!

编辑:如果我通过var query =(...)创建查询的方式与CompiledQuery.Compile内部相同,那么这就是生成的SQL:

Take

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不适用于我的扩展方法。互联网上关于这个主题的信息几乎不存在。

1 个答案:

答案 0 :(得分:3)

我认为编译的查询必须可以翻译成SQL,而扩展方法不能这样。如果您对“常规”查询创建的SQL进行概要分析,您可能会发现它正在选择整个表,以便它可以将所有行提供给您的扩展方法。

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

由于Skip,OrderBy也是一个问题。你需要使这个可以转换为SQL或LINQ必须返回所有行,以便在客户端过滤它们。

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

编辑:

我想我假设你的扩展方法没有构建表达式树。抱歉。

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

看起来像MethodCallExpression是个问题。

  

代码有点长,无法发布   在这里,但类似于tomasp.net的   扩张者,我访问每一个表达   表达式树,如果节点是   一个调用的MethodCallExpression   返回表达式的方法   树,我取代它   MethodCall表达式的表达式   通过调用方法返回的树。

因此,问题在于编译查询时,不执行该方法,因此没有表达式树可以转换为SQL。