C#LINQ。没有使用DocumentDb CreateDocumentQuery

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

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

从这里我所做的就是以下LINQ查询:

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

我收到以下错误:

 "Method 'Any' is not supported." 

我去了代码引用的页面,看看支持什么,但我没有看到它说不支持Any(),所以我可能做错了。 任何帮助表示赞赏。

UPDATE

这对我来说真的很奇怪,所以我打破了它,看看从两个结果返回的内容是为了更好地调试问题:

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

由于某些原因,这不起作用,因为我将它转换为列表,因此它运行查询两次 – 但至少certificateAny()和Select()在技术上应该有效。

针对IQueryable LINQ查询最大的困惑之一是它们看起来与针对IEnumerable查询完全相同。 好吧,前者使用Expression>只要后者使用Func<..> ,但除非使用显式声明,否则这不是那么引人注意并且似乎并不重要。 但是,最大的不同在于运行时。 成功编译IEnumerable查询后,在运行时它就可以正常工作,而IQueryable则不然。 IQuaryable查询实际上是一个表达式树,由查询提供程序在运行时处理。 从一方面来看,这是一个很大的好处,从另一方面来说,因为查询提供程序不参与查询编译时(所有方法都是由Queryable类提供的扩展方法),所以无法知道提供程序是否支持某些构造/方法或直到运行时。 使用Linq to Entities的人非常清楚。 为了使事情更难,没有明确的文档,具体的查询提供程序支持什么,更重要的是,它不支持(正如您从“提供的支持”链接中注意到的那样)。

解决方案是什么(为什么你的第二个代码有效)

诀窍是针对IQueryable编写最大可能(由查询提供程序支持)查询部分,然后切换到IEnumerable并完成剩下的工作(记住,一旦编译, IEnumerable查询就可以了) 。 该开关由AsEnumerable()调用执行。 这就是你的第二个代码正常工作的原因 – 因为不支持Any方法在DocumentDb查询提供程序上下文中不再存在。 请注意,不需要ToList调用,并且查询不会执行两次 – 实际上这种方式没有单个查询,而是两个 – 一个在数据库中,一个在内存中。 所以这样的事情就足够了

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

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

从文档中可以清楚地看出,但答案是: 确切地(并且仅限于)那里包含的内容。 换句话说,唯一支持的查询运算符(或更好地说可查询或Enumerable扩展方法)是

  • 选择
  • 的SelectMany
  • 哪里
  • 排序依据
  • OrderByDescending

正如您所看到的,它非常有限。 忘记加入和分组运算符, AnyContainsCountFirstLast等。唯一的好处是它很容易记忆:)

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

我正在使用最新的Azure DocumentDB nuget目标.Net 4.6。

  

这是示例代码,对我来说很好。

 using System.Collections.Generic; using System.Linq; using Microsoft.Azure.Documents.Client; using Microsoft.Azure.Documents.Linq; var book = client.CreateDocumentQuery(collectionLink) .Where(b => b.Title == "War and Peace") .Where(b => b.Publishers.Any(p => p.IsNormalized())) .AsEnumerable().FirstOrDefault(); public class Book { [JsonProperty("title")] public string Title { get; set; } public Author Author { get; set; } public int Price { get; set; } public List Publishers { get; set; } 

}

 public class Author { public string FirstName { get; set; } public string LastName { get; set; } } 

你应该尝试在这里使用IEnumerable.Contains 链接

 DbHelper.Client.CreateDocumentQuery(collection.DocumentsLink) .Where(i => i.type == "art") .Where(i => i.Products .Select(p => p.Name).Contains(productType)) .AsEnumerable() .ToList(); 

目前最高性能的解决方案是使用SQL语法,因为它允许文档DB使用集合的索引。
例:

 SELECT a FROM a JOIN p in a.Products WHERE ARRAY_CONTAINS(a.Id, 'art') AND p.Name = 'My Product Type' 

缺点是您可能会得到非唯一的结果,并且必须区分客户端的结果。

要将此问题纳入DocumentDB,将有助于对以下项目进行投票: https : //feedback.azure.com/forums/263030-documentdb/suggestions/14829654-support-sub-query-functions-like-exists-not -存在

你为什么不尝试这个呢?

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