programing

C# LINQ.DocumentDb CreateDocument에서 작업하지 않는 모든 항목쿼리

skycolor 2023. 5. 17. 22:40
반응형

C# LINQ.DocumentDb CreateDocument에서 작업하지 않는 모든 항목쿼리

특정 유형의 제품이 있는 아트에 문의하려고 합니다.제 미술 모델은 다음과 같습니다.

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

여기서 제가 하고 있는 것은 다음 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();

다음 오류가 발생합니다.

"Method 'Any' is not supported."

코드가 지원되는 항목을 확인하기 위해 참조하는 페이지로 이동했지만 Any()가 지원되지 않는다고 표시되지 않아 잘못된 작업을 수행하고 있는 것 같습니다.어떤 도움이든 감사합니다.

갱신하다

이것은 저에게 정말 이상한 일입니다. 그래서 저는 이 문제를 더 잘 디버그하기 위해 두 결과에서 무엇이 반환되는지 보기 위해 이 문제를 분리했습니다.

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()가 기술적으로 작동해야 한다는 증거입니다.

다음에 대한 LINQ 쿼리의 가장 큰 혼란 중 하나입니다.IQueryable<T>그들이 정확히 같은 것처럼 보인다는 것입니다.IEnumerable<T>음, 전자는 사용하고 있습니다.Expression<Func<..>>후자가 사용될 때마다Func<..>그러나 명시적 선언을 사용하는 경우를 제외하고는 이는 그다지 눈에 띄지 않으며 중요하지 않아 보입니다.하지만, 큰 차이는 런타임에 나타납니다.

원스 더IEnumerable<T>쿼리가 성공적으로 컴파일되었습니다. 런타임에 작동합니다. 이 경우는 그렇지 않습니다.IQueryable<T>.aIQueryable<T>쿼리는 실제로 쿼리 공급자가 런타임에 처리하는 식 트리입니다.

쿼리 제공자가 쿼리 컴파일 시간에 관여하지 않기 때문에 한쪽에서, 다른 쪽에서 이것은 큰 이점입니다. (모든 메서드는 다음과 같이 확장 메서드로 제공됩니다.)Queryable클래스), 공급자가 일부 구성/구성 요소를 지원하는지 여부를 런타임까지 알 수 없습니다.Link to Entities를 사용하는 사람들은 그것을 잘 알고 있습니다.문제를 더 어렵게 만드는 것은 특정 쿼리 공급자가 지원하는 것과 더 중요하게는 지원하지 않는 것에 대한 명확한 문서가 없습니다(제공한 "지원되는 항목" 링크에서 알 수 있듯이).

해결책은 무엇입니까?(및 두 번째 코드가 작동하는 이유)

이 방법은 가능한 최대 쿼리 부분(즉, 쿼리 공급자가 지원하는)을 작성하는 것입니다.IQueryable<T>다음으로 전환합니다.IEnumerable<T>나머지 작업을 수행합니다(기본적으로, 일단 컴파일되면,IEnumerable<T>쿼리가 작동합니다).는 스치는다같수다니행됩이과에 의해 됩니다.AsEnumerable()call. 두 되지 않는 unsupported 코작동가다합니드그번두째래서▁un▁is▁call▁because다▁code▁-니동합작▁second▁workingsupported▁and▁your▁that. 지원되지 않기 때문입니다.Any메서드가 DocumentDb 쿼리 공급자 컨텍스트에 더 이상 없습니다.:ToList호출할 필요가 없으며 쿼리가 두 번 실행되지 않습니다. 실제로 이 방법으로는 단일 쿼리가 없고 데이터베이스와 메모리에 하나씩 있는 두 개의 쿼리가 있습니다.

따라서 다음과 같은 것으로 충분합니다.

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 쿼리 공급자가 실제로 지원하는 것은 무엇입니까?

설명서에서는 명확하지 않지만, 정답은 다음과 같습니다. 정확히 (그리고 유일하게) 거기에 포함된 내용입니다. 연산자 더 잘 말하면 즉게지또입쿼는연리원산되자니다표나현더은유일하는또입▁(▁operators▁say▁in▁the,니다▁supportedor즉▁query연▁only()입니다.Queryable또는Enumerable 메서드는 "확장 메서드"입니다.

  • 선택한다.
  • 다수 선택
  • 어디에
  • 주문 기준
  • 내림차순 정렬

보시다시피 매우 제한적입니다. 연산자는 , 조인및는잊십시오리어버자.Any,Contains,Count,First,Last단입니다 :)등 단 한가지 좋은 점은 쉽게 외울 수 있다는 것입니다 :)

내가 그걸 어떻게 알아?문서에서 명확하지 않은 것이 있을 때는 보통 시행착오나 디컴파일러를 사용합니다.이 경우 전자는 해당되지 않으므로 후자를 사용했습니다. 클래스의 .DocumentQueryEvaluator에의 에.Microsoft.Azure.Documents.Client.dll.

최신 Azure 문서를 사용하고 있습니다.DB nug 대상입니다.넷 4.6.

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

여기 제게 잘 작동하는 샘플 코드가 있습니다.

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; }
}

은 보오시십해를 해 봐야 .IEnumerable.Contains 를 하세요.

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

문서 DB는 컬렉션의 색인을 사용할 수 있으므로 현재 가장 성능이 뛰어난 솔루션은 SQL 구문을 사용하는 것입니다.
예:

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-exist

이것을 시도해 보는 게 어때요?

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

언급URL : https://stackoverflow.com/questions/33839854/c-sharp-linq-any-not-working-on-documentdb-createdocumentquery

반응형