C#LINQ.任何无法在DocumentDb CreateDocumentQuery上使用的文件 [英] C# LINQ .Any not working on DocumentDb CreateDocumentQuery

查看:60
本文介绍了C#LINQ.任何无法在DocumentDb CreateDocumentQuery上使用的文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试查询具有某种类型产品的Art.这是我的Art模型:

I'm trying to query Art that has a product of a certain type. Here is my model for Art:

  public string Title { get; set; }
  public string Description { get; set; }
  public List<Product> Products { get; set; }
  public string PaintedLocation { get; set; }

从这里开始,我要做的是以下LINQ查询:

From here all I'm doing is the following LINQ query:

List<Art> items = DocumentDbHelper.Client.CreateDocumentQuery<Art>(collection.DocumentsLink)
                               .Where(i => i.type == "art")
                               .Where(i => i.Products.Any(p => p.Name == productType))
                               .AsEnumerable()
                               .ToList();

我收到以下错误:

"Method 'Any' is not supported."

我转到了代码引用的页面,以查看支持什么,但我看不到它说不支持Any(),所以我可能做错了什么.感谢您的帮助.

I went to the page that the code references for seeing what is supported but I don't see it saying that Any() is not supported, so I'm probably doing something incorrect. Any help is appreciated.

更新

这对我来说真的很奇怪,因此我将其分解以查看两个结果返回的内容,以便对此进行更好的调试:

This is really odd to me, so I broke it up to see what was being returned from the two results to better debug the issue to this:

List<Art> items = DocumentDbHelper.Client.CreateDocumentQuery<Art>(collection.DocumentsLink)
                       .Where(i => i.Id.Contains("art"))
                       .AsEnumerable()
                       .ToList();

items = items.Where(i => i.Products.Any(p => p.Name == productType))
             .AsEnumerable()
             .ToList();

出于某种原因,它不是可行的,因为我将其转换为列表,因此它不运行该查询两次,但是至少证明Any()和Select()在技术上可以正常工作

For some reason this works, I'm not a fan of this because since I'm converting it to a list it's running the query twice - but it is at least proof that Any() and Select() should technically work.

推荐答案

与针对IQueryable<T>的LINQ查询最大的困惑之一是,它们看起来与针对IEnumerable<T>的查询完全相同.好吧,前者每当后者使用Func<..>时都使用Expression<Func<..>>,但是除非有人使用显式声明,否则它并不那么引人注目,而且似乎并不重要.但是,最大的区别在于运行时.成功编译IEnumerable<T>查询后,在运行时它就会起作用,而IQueryable<T>则不是这种情况. IQuaryable<T>查询实际上是一个表达式树,在运行时由查询提供程序进行处理.一方面,这是一个很大的好处,另一方面,由于查询编译时不涉及查询提供程序(所有方法都由Queryable类作为扩展方法提供),因此无法知道提供程序是否直到运行时才支持某种构造/方法.使用Linq to Entities的人都非常了解.更麻烦的是,没有明确的文档来说明特定查询提供程序所支持的内容,更重要的是,它不支持哪些内容(正如您从所提供的受支持的内容"链接中所注意到的那样).

One of the biggest confusion with LINQ queries against IQueryable<T> is that they look exactly the same as queries against IEnumerable<T>. Well, the former is using Expression<Func<..>> whenever the later is using Func<..>, but except if one is using explicit declarations this is not so noticeable and seems unimportant. However, the big difference comes at runtime. Once the IEnumerable<T> query is successfully compiled, at runtime it just works, which is not the case with IQueryable<T>. A IQuaryable<T> query is actually an expression tree which is processed at runtime by the query provider. From one side this is a big benefit, from the other side, since the query provider is not involved at query compile time (all the methods are provided as extension methods by Queryable class), there is no way to know if the provider supports some construct/method or not until runtime. People that use Linq to Entities know that very well. To make the things harder, there is no clear documentation what the specific query provider supports and more importantly, what it doesn't support (as you noticed from the "what is supported" link you provided).

解决方案(以及第二个代码为何起作用)

What's the solution (and why your second code works)

诀窍是针对IQueryable<T>编写最大可能的查询部分(即由查询提供程序支持),然后切换到IEnumerable<T>并进行其余工作(请记住,一旦编译,IEnumerable<T>查询就可以了).通过AsEnumerable()调用执行切换.这就是您的第二个代码起作用的原因-因为DocumentDb查询提供程序上下文中不再存在不受支持的Any方法.请注意,不需要ToList调用,并且查询不会执行两次-实际上,这种方式不存在单个查询,而是两个-数据库中的一个查询和内存中的一个查询.所以像这样的东西就足够了

The trick is to write the maximum possible (i.e.supported by the query provider) query part against the IQueryable<T>, and then switch to IEnumerable<T> and do the rest (remember, once compiled, IEnumerable<T> query just works). The switch is performed by AsEnumerable() call. And that's why your second code is working - because unsupported Any method is no more in the DocumentDb query provider context. Note that ToList call is not needed and the query is not executed twice - in fact this way there is no single query, but two - one in database and one in memory. So something like this would be sufficient

List<Art> items = DocumentDbHelper.Client.CreateDocumentQuery<Art>(collection.DocumentsLink)
                               .Where(i => i.type == "art")
                               .AsEnumerable() // The context switch!
                               .Where(i => i.Products.Any(p => p.Name == productType))
                               .ToList();

最后,DocumentDb查询提供程序真正支持的是什么

Finally, what really is supported by the DocumentDb query provider

从文档中还不清楚,但是答案是:完全(且仅)包含在其中.换句话说,唯一受支持的查询运算符(或更确切地说是QueryableEnumerable扩展方法)是

It's not quite clear from the documentation, but the answer is: exactly (and only) what is included there. In other words, the only supported query operators (or better say Queryable or Enumerable extension methods) are

  • 选择
  • SelectMany
  • 哪里
  • OrderBy
  • OrderByDescending

您可能会看到,它非常有限.忘记加入和分组运算符,AnyContainsCountFirstLast等.唯一的好处是它易于记忆:)

As you may see, it's very limited. Forget about join and grouping operators, Any, Contains, Count, First, Last etc. The only good thing is that it's easy memorizable :)

我怎么知道?好吧,像往常一样,当文档中有不清楚的地方时,可以使用试错法或反编译器.显然,在这种情况下,前者不适用,因此我使用了后者.如果您好奇,请使用自己喜欢的反编译器,并检查Microsoft.Azure.Documents.Client.dll中内部类DocumentQueryEvaluator的代码.

How do I know that? Well, as usual when something is unclear from the documentation, one either use trial and error or decompiler. Apparently in this case the former is not applicable, so I've used the later. If you are curious, use your favorite decompiler and check the code of the internal class DocumentQueryEvaluator inside the Microsoft.Azure.Documents.Client.dll.

这篇关于C#LINQ.任何无法在DocumentDb CreateDocumentQuery上使用的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆