query queries example cosmosdb c# linq azure azure-cosmosdb

c# - example - queries in cosmos db



C#LINQ. Cualquier no funciona en DocumentDb CreateDocumentQuery (5)

¿Por qué no pruebas este?

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

Estoy tratando de consultar Arte que tiene un producto de cierto tipo. Aquí está mi modelo para el arte:

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

Desde aquí todo lo que estoy haciendo es la siguiente consulta LINQ:

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();

Obtuve el siguiente error:

"Method ''Any'' is not supported."

Fui a la página a la que hace referencia el código para ver qué se admite, pero no veo que diga que no se admite Any (), por lo que es probable que esté haciendo algo incorrecto. Cualquier ayuda es apreciada.

ACTUALIZAR

Esto es realmente extraño para mí, así que lo dividí para ver qué se estaba devolviendo de los dos resultados para depurar mejor el problema:

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();

Por alguna razón esto funciona, no soy un fanático de esto porque, al convertirlo en una lista, está ejecutando la consulta dos veces, pero al menos es una prueba de que Any () y Select () deberían funcionar técnicamente.


Debes intentar usar el enlace IEnumerable.Contains aquí

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


Estoy usando el último nuget de Azure DocumentDB que apunta .Net 4.6.

<package id="Microsoft.Azure.DocumentDB" version="1.5.0" targetFramework="net46" />

Aquí está el código de ejemplo que está funcionando bien para mí.

using System.Collections.Generic; using System.Linq; using Microsoft.Azure.Documents.Client; using Microsoft.Azure.Documents.Linq; var book = client.CreateDocumentQuery<Book>(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<string> Publishers { get; set; }

}

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


La solución más eficaz actualmente es utilizar la sintaxis SQL, ya que permite que la base de datos del documento utilice el índice de la colección.
ejemplo:

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

La desventaja es que podría obtener resultados no únicos y tener que distinguir el resultado del lado del cliente.

Para incluir este problema en DocumentDB, sería útil votar el siguiente elemento: https://feedback.azure.com/forums/263030-documentdb/suggestions/14829654-support-sub-query-functions-like-exists-not-exist


Una de las mayores confusiones con las consultas LINQ contra IQueryable<T> es que se ven exactamente igual que las consultas contra IEnumerable<T> . Bueno, el primero usa Expression<Func<..>> siempre que el último usa Func<..> , pero excepto si uno usa declaraciones explícitas, esto no es tan notable y no parece importante. Sin embargo, la gran diferencia viene en tiempo de ejecución. Una vez que la consulta IEnumerable<T> se compila correctamente, en tiempo de ejecución simplemente funciona, lo que no es el caso con IQueryable<T> . Una consulta IQuaryable<T> es en realidad un árbol de expresiones que el proveedor de consultas procesa en tiempo de ejecución. De un lado, esto es un gran beneficio, del otro lado, ya que el proveedor de consultas no participa en el tiempo de compilación de la consulta (todos los métodos se proporcionan como métodos de extensión por clase Queryable ), no hay manera de saber si el proveedor admite algunos Construir / método o no hasta el tiempo de ejecución. La gente que usa Linq para Entidades lo sabe muy bien. Para hacer las cosas más difíciles, no hay documentación clara sobre qué admite el proveedor de consultas específico y, lo que es más importante, qué es lo que no admite (como notó en el enlace "qué es compatible" que proporcionó).

Cuál es la solución (y por qué funciona tu segundo código)

El truco consiste en escribir la parte de consulta máxima (compatible con el proveedor de consultas) en IQueryable<T> , y luego cambiar a IEnumerable<T> y hacer el resto (recuerde, una vez compilada, la consulta IEnumerable<T> simplemente funciona) . El interruptor se realiza mediante AsEnumerable() llamada AsEnumerable() . Y es por eso que su segundo código está funcionando, porque no es compatible. Any método ya no existe en el contexto del proveedor de consultas DocumentDb. Tenga en cuenta que la llamada ToList no es necesaria y que la consulta no se ejecuta dos veces; de hecho, de esta manera no hay una sola consulta, sino dos: una en la base de datos y otra en la memoria. Así que algo como esto sería suficiente

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();

Finalmente, lo que realmente es compatible con el proveedor de consultas DocumentDb

No queda muy claro en la documentación, pero la respuesta es: exactamente (y solo) lo que se incluye allí. En otras palabras, los únicos operadores de consulta compatibles (o, mejor, los métodos de extensión Queryable o Enumerable ) son

  • Seleccionar
  • SelectMany
  • Dónde
  • OrderBy
  • OrderByDescending

Como puedes ver, es muy limitado. Olvídese de unirse y agrupar operadores, Any , Contains , Count , First , Last , etc. Lo único bueno es que es fácil de memorizar :)

¿Cómo sé eso? Bueno, como de costumbre, cuando algo no está claro en la documentación, uno puede usar prueba y error o descompilar. Al parecer, en este caso, el primero no es aplicable, por lo que he usado el último. Si tiene curiosidad, use su descompilador favorito y verifique el código de la clase interna DocumentQueryEvaluator dentro de Microsoft.Azure.Documents.Client.dll .