Ale*_*lex 8 c# linq expression-trees linq-to-sql compiled-query
我有C#扩展方法IQueryable,例如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));
Run Code Online (Sandbox Code Playgroud)
FindCustomersRegisteredAfter(int year)方法是一种采用IQueryable并返回相同的扩展方法.该OrderBy方法也是一种扩展方法(System.Linq.Dynamic),它根据字符串创建动态表达式(例如"FirstName ASC"将对字段FirstName进行排序).Skip并且Take是内置方法.
上面(不是编译查询,但常规查询)工作完美.一旦我把它放在编译的查询中,我就会遇到以下错误:
方法 'System.Linq.IQueryable`1 [Domain.Customer] FindCustomersRegisteredAfter [客户](System.Linq.IQueryable`1 [Domain.Customer],Int32)将' 没有支持转换为SQL.
再次,如果查询是非编译的,只是常规的LINQ查询,这将完美地工作.只有在CompiledQuery.Compile()内部出现错误.
救命??!
编辑:如果我通过var query =(...)创建查询的方式与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]
Run Code Online (Sandbox Code Playgroud)
所以你看到SQL完全可以翻译,所以我只需要填写@ p0,@ p1和@ p2就可以重复工作!CompiledQuery.Compile有什么问题?!?
更新:我理解OrderBy无法工作(因为它不是@p参数).我仍在试图弄清楚为什么CompiledQuery.Compile不适用于我的扩展方法.互联网上关于该主题的信息几乎不存在.
我相信编译的查询必须可转换为 SQL,而您的扩展方法则不能。如果您分析由“常规”查询创建的 SQL,您可能会发现它正在选择整个表,以便它可以将所有行输入到您的扩展方法中。
您最好将过滤逻辑放入查询中(作为表达式树的一部分),以便将其转换为 SQL 并在服务器端运行。
由于 Skip,OrderBy 也是一个问题。您需要将其转换为 SQL 或 LINQ 将必须返回所有行,以便在客户端过滤它们。
如果您无法将这些表达为 LINQ 表达式,请考虑在服务器上创建 SQL 函数并将它们映射到 DataContext。LINQ 将能够将这些转换为 T-SQL 函数调用。
编辑:
我想我假设你的扩展方法没有构建表达式树。对不起。
看来 MethodCallExpression 是问题所在。
在这里发布的代码有点长,但与 tomasp.net 的扩展器类似,我访问表达式树中的每个表达式,如果节点是调用返回表达式树的方法的 MethodCallExpression,我会将该 MethodCallExpression 替换为通过调用该方法返回的表达式树。
因此,问题似乎在于编译查询时,该方法未执行,因此没有表达式树可转换为 SQL。
| 归档时间: |
|
| 查看次数: |
2157 次 |
| 最近记录: |