gpt4 book ai didi

c# - LINQ-to-SQL 编译查询问题(用作未编译查询)

转载 作者:太空狗 更新时间:2023-10-29 19:44:42 26 4
gpt4 key购买 nike

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

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



 private static Func
    
     >
     
CQFindAll =
CompiledQuery.Compile((MyDataContext dc, SearchInfo 信息) =>
dc.Contacts.Select(c => c).FindCustomersRegisteredAfter(info.RegYear)
.OrderBy(信息.OrderInfo)
.Skip(信息.SkipCount)
.Take(信息.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 query = (...) 以与 CompiledQuery.Compile 内部相同的方式创建查询,这是生成的 SQL:



SELECT [t1].[Id], [t1].[FirstName], [t1].[LastName],
[t1].[RegYear], [t1].[DeletedOn]
从 (
选择 ROW_NUMBER() OVER (ORDER BY [t0].[LastName]) AS [ROW_NUMBER],
[t0].[Id], [t0].[FirstName], [t0].[LastName], [t0].[RegYear],
[t0].[DeletedOn]
FROM [dbo].[联系人] AS [t0]
WHERE ([t0].[RegYear] > @p0) AND ([t0].[DeletedOn] 为 NULL)
) 作为 [t1]
WHERE [t1].[ROW_NUMBER] 在@p1 + 1 和@p1 + @p2 之间
按 [t1].[ROW_NUMBER] 排序

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

更新:我知道 OrderBy 不能工作(因为它不是 @p 参数)。我仍在尝试弄清楚为什么 CompiledQuery.Compile 不能与我的扩展方法一起使用。互联网上关于此主题的信息几乎不存在。

最佳答案

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

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

OrderBy 也是一个问题,因为 Skip。您需要将其转换为 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。

关于c# - LINQ-to-SQL 编译查询问题(用作未编译查询),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1420672/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com