哪些方法可以关闭已编译的查询

发布于 2024-09-09 09:28:04 字数 436 浏览 1 评论 0原文

我们知道,您不能向已编译的查询添加诸如 .Where().First() 之类的额外子句,因为这会更改查询并强制重新编译。我想知道哪些方法可用于“关闭”已编译的查询。

我知道大多数人使用 .AsEnumerable().ToList(),但是还有哪些其他方法也有效?我可以使用 .AsQueryable(),还是这是一个无操作?

哪个性能更好?我知道 .AsEnumerable().ToList() 更快,但如果我想要一个 IQueryable,就是 .AsEnumerable() .AsQueryable().ToList() 更好吗?

As we know you can't add an extra clause like .Where() or .First() to a compiled query, because that changes the query and forces a recompile. What I would like to know is which methods can be used to "close" a compiled query.

I know most people use either .AsEnumerable() or .ToList(), but which other methods work as well? Can I use .AsQueryable(), or is this a no-op?

And which is better performance-wise? I know .AsEnumerable() is faster than .ToList(), but if I want an IQueryable, is .AsEnumerable().AsQueryable() better than .ToList()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

吖咩 2024-09-16 09:28:04

在大多数情况下,AsEnumerable().AsQueryable() 可能就是您想要的,因为:

  • 通过执行显式 AsEnumerable(),您不会面临以下风险:底层实现使 AsQueryable() 成为无操作,从而破坏您关闭查询的尝试。我并不是说今天的 EF 使 AsQueryable() 成为无操作(据我所知,事实并非如此),只是说这种行为——要么无操作,要么透明地调用AsEnumerable()——没有记录,所以依赖它是不安全的。
  • ToList() 不同,AsEnumerable() 不会将整个结果集加载到内存中以进行查询。这对于大型结果集非常重要。从理论上讲,对于较小的结果集,使用 ToList() 可能会有一些优势(例如,优化的 ToList() 实现从底层提供程序中提取大块数据,而枚举涉及更多上下文切换),但这似乎不太可能且很难依赖于跨提供者和版本,而 AsEnumerable() 的大结果集优势将永远存在。

我确实喜欢调用 ToList() 的一种情况是当我明确想要强制立即执行查询时。例如,如果我想在方法中更早地捕获查询中的错误,以便稍后可以简化错误处理,或者我想在继续查询的其余部分之前验证所有基础数​​据。或者,如果查询被分成两部分时更容易测试。我永远不会这样做,除非我知道我的记录集会很小,因为在数百万行查询上调用 ToList() 会耗尽您的 RAM。

要回答您的其他问题,请参阅 MSDN 上 LINQ 文档中的转换数据类型详细说明哪些 LINQ 方法强制执行查询。根据该页面,ToArray()ToDictionary()ToList()ToLookup() 全部强制执行查询。

相比之下,AsEnumerable() 不会强制立即执行查询,但会“关闭”查询(此处使用您的术语,不确定是否有官方术语)。根据 http://msdn.microsoft.com/en-us/library/bb335435。 .aspx:

AsEnumerable 方法可以
用于隐藏自定义方法和
而是进行标准查询
可用的运算符。

换句话说,运行 AsEnumerable 将强制所有调用(如 Take()Where())使用通用 LINQ 实现,而不是任何会导致重新编译的自定义实现。

In most cases, AsEnumerable().AsQueryable() is probably what you want, because:

  • By doing an explicit AsEnumerable(), you're not running the risk of the underlying implementation making AsQueryable() into a no-op, thereby ruining your attempt to close the query. I'm not saying that today's EF makes AsQueryable() a no-op (as far as I can tell, it doesn't), only that the behavior-- either no-op or transparently call AsEnumerable()-- isn't documented so relying on it isn't safe.
  • AsEnumerable(), unlike ToList(), doesn't load your entire resultset in memory in order to query it. This matters a lot with large resultsets. It's theoretically possible that for smaller resultsets, there could be some advantage to using ToList() (e.g. an optimized ToList() implementation pulls data in big chunks from the underlying provider, while enumeration involves more context switching) but that seems unlikely and hard to depend on across providers and versions, while the large-resultset advantage of AsEnumerable() will live forever.

The one case where I do like calling ToList() is when I explicitly do want to force a query to execute right now. For example, if I want to catch errors in a query earlier in a method so that I can simplify error handling later, or I want to validate all the underlying data before continuing with the rest of the query. Or if the query is more easily tested when chopped in two. And I'll never do this, unless I know that my recordset is going to be small, since calling ToList() on a multi-million-row query will kill your RAM.

To answer your other question, Converting Data Types in the LINQ documentation on MSDN details which LINQ methods force query execution. According to that page, ToArray(), ToDictionary(), ToList(), and ToLookup() all force query execution.

AsEnumerable(), by contrast, doesn't force immediate query execution, but does "close" the query (using your term here, not sure if there's an official term for this). Per http://msdn.microsoft.com/en-us/library/bb335435.aspx:

the AsEnumerable method can
be used to hide the custom methods and
instead make the standard query
operators available.

In other words, running AsEnumerable will force all calls like Take() and Where() to use the generic LINQ implementations and not anythign custom which would cause a re-compile.

暖阳 2024-09-16 09:28:04

哪些方法可用于“关闭”已编译的查询。

返回序列的方法使用延迟执行,除非该方法类似于 ToXYZWhere选择TakeSkipGroupByOrderBy< /code> 等属于此范围。返回单个对象的方法强制执行查询,例如 FirstSingleToListToArrayToDictionaryToLookupAnyAll 等。有关更多信息,请参阅这个优秀的线程:Linq - 找出是否延迟执行的最快方法是什么?

我知道大多数人使用 .AsEnumerable() 或 .ToList(),但是还有哪些其他方法也有效?我可以使用 .AsQueryable(),还是这是一个空操作?

他们都是不同的。贾斯汀有一个宏大的解释。您可能还想查看:.ToList() 之间有什么区别, .AsEnumerable(), AsQueryable()? 这有一个很好的答案。


一般来说,您可以通过查看方法本身的名称来了解该方法的语义。名为 AsSomething 的方法意味着它不执行任何操作,只是将输入作为某物返回。这可能涉及也可能不涉及返回一个新对象,但以某种方式维护了引用。例如,List.AsEnumerable() 只是对 IEnumerable 进行强制转换(当然它在 linq 上下文中具有更大的含义)。您可以将其转换回 List 并对其进行变异以反映各处的更改。测试它:

var list = new List<int> { 1, 2 };
var enum = list.AsEnumerable();
var newlist = enum as List<string>;
newlist.Add(3);
//print enum.Count() -> 3

虽然方法看起来像 ToSomething,但您会得到一个全新的对象,通常会转换为其他对象。

var list = new List<int> { 1, 2 };
var newlist = list.ToList();
newlist.Add(3);
//print list.Count -> 2

让我们考虑一下 linq 上下文之外的东西。 object.ToString() 产生新的字符串表示形式(字符串无论如何都是不可变的,所以这有点毫无意义)。一个有趣的语义是 List.AsReadonly ,它返回一个新的 ReadOnlyCollection 实例,但改变其外部的列表会更改 的内部列表>ReadOnlyCollection 也是如此,因此命名为 AsReadonly

var list = new List<int> { 1, 2 };
var readonlylist = list.AsReadonly();
list.Add(3);
//print readonlylist.Count -> 3

which methods can be used to "close" a compiled query.

Methods that return a sequence use deferred execution, unless the method is something like ToXYZ. Where, Select, Take, Skip, GroupBy and OrderBy etc falls under this. Methods that return a single object forces execution of query, like First, Single, ToList and ToArray, ToDictionary, ToLookup, Any, All etc. See this excellent thread for more: Linq - What is the quickest way to find out deferred execution or not?

I know most people use either .AsEnumerable() or .ToList(), but which other methods work as well? Can I use .AsQueryable(), or is this a no-op?

They all are different. Justin has a grand explanation. You might also want to see: What's the difference(s) between .ToList(), .AsEnumerable(), AsQueryable()? which has a good answer.


In general, you can understand the semantics of a method by seeing the name of the method itself. A method named AsSomething implies it does nothing but returns the input as something. That may or may not involve returning a new object, but a reference is somehow maintained. For instance, aList<T>.AsEnumerable() merely does a cast to IEnumerable<T>(of course it has bigger meaning in linq context). You can cast it back to List<T> and mutate it reflecting the change everywhere. To test it:

var list = new List<int> { 1, 2 };
var enum = list.AsEnumerable();
var newlist = enum as List<string>;
newlist.Add(3);
//print enum.Count() -> 3

While methods that look like ToSomething, you get a totally new object often transformed to something else.

var list = new List<int> { 1, 2 };
var newlist = list.ToList();
newlist.Add(3);
//print list.Count -> 2

Let's consider something outside the context of linq. object.ToString() results in new string representation (strings are anyway immutable so thats a bit pointless). An interesting semantics is that of List<T>.AsReadonly which returns a new ReadOnlyCollection<T> instance, but mutating the list outside of it changes the internal list of ReadOnlyCollection<T> too, hence the naming AsReadonly.

var list = new List<int> { 1, 2 };
var readonlylist = list.AsReadonly();
list.Add(3);
//print readonlylist.Count -> 3
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文