![](/img/trans.png)
[英]What collection should I use in a linq-to-sql query? Queryable vs Enumerable vs List
[英]LINQ to Entities / LINQ to SQL: switching from server (queryable) to client (enumerable) in the middle of a query comprehension?
在许多情况下,我想在服务器端进行一些过滤(有时是投影),然后切换到客户端以进行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;
然而,有很多次这是更多的代码/麻烦,而不是真正的价值。 我真的很想在中间做一个“切换到客户端”。 我已经尝试了各种使用查询延续的方法,但是在第一个查询结束时执行'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;
好的,首先你绝对不应该在这里使用代码 。 它是由经过训练的特技仓鼠编写的,他们在处理这种性质的代码时受过训练而不会呕吐。
你绝对应该选择一个你知道的选项:
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;
}
}
当然,如果你使用的是普通的方法语法,那就没问题了:
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);
如果你坚持使用查询语法,你就不会使用一些括号,但除此之外,你当然可以这样做:
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;
重用变量名称t
不会导致任何问题; 我测试了它。
服务器/客户端是什么意思?
我想你的意思是你从服务器获得一些集合,然后执行LINQ-to-entity中没有的额外过滤。 试试这个:
var items =
context.Table.Where(t => t.Col1 = 123 && t.Col2 = "blah").ToList()
.Where(t => t.Col3.Split('/').Last() == "whatever")
.Select(t => t.Col4).ToList();
您想使用更抽象的语法来更好地控制服务器与本地执行吗? 对不起 - 这不可行。
考虑查询理解中的范围问题。
from c in context.Customers
from o in c.Orders
from d in o.Details
asLocal
where //c, o and d are all in scope, so they all had to be hydrated locally??
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.