Jam*_*ing 10 c# linq linq-to-objects linq-to-entities linq-to-sql
在许多情况下,我想在服务器端进行一些过滤(有时是投影),然后切换到客户端以进行LINQ提供程序本身不支持的操作.
天真的方法(基本上就是我现在所做的)就是把它分解成多个查询,类似于:
var fromServer = from t in context.Table
where t.Col1 = 123
where t.Col2 = "blah"
select t;
var clientSide = from t in fromServer.AsEnumerable()
where t.Col3.Split('/').Last() == "whatever"
select t.Col4;
Run Code Online (Sandbox Code Playgroud)
然而,有很多次这是更多的代码/麻烦,而不是真正的价值.我真的很想在中间做一个"切换到客户端".我已经尝试了各种使用查询延续的方法,但是在第一个查询结束时执行'select t into foo'后,foo仍然是一个单独的项目,而不是集合,所以我不能AsEnumerable()它.
我的目标是能够写出更像:
var results = from t in context.Table
where t.Col1 = 123
where t.Col2 = "blah"
// Magic happens here to switch to the client side
where t.Col3.Split('/').Last() == "whatever"
select t.Col4;
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 20
好的,首先你绝对不应该在这里使用代码.它是由经过训练的特技仓鼠编写的,他们在处理这种性质的代码时受过训练而不会呕吐.
你绝对应该选择一个你知道的选项:
IEnumerable<T>
那么您不需要调用AsEnumerable
- 如果您有一个匿名类型作为课程的元素类型,那将无效)AsEnumerable
AsEnumerable
呼叫适合.但是,您可以使用查询表达式的翻译方式来做一些魔术.您只需要使一个标准查询运算符与查询表达式中的表示具有不同的转换.这里最简单的选择可能就是"Where".只要写你自己的扩展方法服用IQueryable<T>
和Func<T, SomeType>
地方SomeType
不bool
和你离开.这是一个例子,首先是hack本身,然后是它的示例使用......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
public static class QueryHacks
{
public static readonly HackToken TransferToClient = HackToken.Instance;
public static IEnumerable<T> Where<T>(
this IQueryable<T> source,
Func<T, HackToken> ignored)
{
// Just like AsEnumerable... we're just changing the compile-time
// type, effectively.
return source;
}
// This class only really exists to make sure we don't *accidentally* use
// the hack above.
public class HackToken
{
internal static readonly HackToken Instance = new HackToken();
private HackToken() {}
}
}
public class Test
{
static void Main()
{
// Pretend this is really a db context or whatever
IQueryable<string> source = new string[0].AsQueryable();
var query = from x in source
where x.StartsWith("Foo") // Queryable.Where
where QueryHacks.TransferToClient
where x.GetHashCode() == 5 // Enumerable.Where
select x.Length;
}
}
Run Code Online (Sandbox Code Playgroud)
当然,如果你使用的是普通的方法语法,那就没问题了:
var results = context.Table
.Where(t => t.Col1 == 123)
.Where(t => t.Col2 == "blah")
.AsEnumerable()
.Where(t => t.Col3.Split('/').Last() == "whatever")
.Select(t => t.Col4);
Run Code Online (Sandbox Code Playgroud)
如果你坚持使用查询语法,你就不会使用一些括号,但除此之外,你当然可以这样做:
var results = from t in (
from t in context.Table
where t.Col1 == 123
where t.Col2 == "blah"
select t
).AsEnumerable()
where t.Col3.Split('/').Last() == "whatever"
select t.Col4;
Run Code Online (Sandbox Code Playgroud)
重用变量名称t
不会导致任何问题; 我测试了它.