DocumentClient在Azure-CosmosDB中返回单个对象

问题描述 投票:0回答:4

如何更改我的方法只返回Cliente类型的一个对象?

我的方法:

public IQueryable <Cliente> GetByEmailCpf(string email, string cpf, string colletionId) 
{
  FeedOptions queryOptions = new FeedOptions {
   MaxItemCount = -1
  };

  IQueryable <Cliente> cliente = client.CreateDocumentQuery <Cliente> (
    UriFactory.CreateDocumentCollectionUri(databaseId, colletionId), queryOptions)
   .Where(x => x.Email == email || x.Cpf == cpf);

  return cliente;
}

DocumentQueryException:查询表达式无效,表达式https://127.0.0.1:8081/dbs/Comosos/colls/Cliente.Where(x =>((x.Email == value(LR.Mobile.Data.Repositories.ModuloProduto.Classes.ClienteRepository + <> c__DisplayClass5_0).email)OrElse(x.Cpf == value(LR) .Mobile.Data.Repositories.ModuloProduto.Classes.ClienteRepository + <> c__DisplayClass5_0).cpf)))。不支持FirstOrDefault()。支持的表达式是'Queryable.Where','Queryable.Select'和'Queryable.SelectMany'

c# linq azure-cosmosdb
4个回答
2
投票

如您的错误所述,您似乎正在尝试使用FirstOrDefault。目前不支持此功能,根据Azure Cosmos反馈网站,目前不是优先事项:

Add support for single entity retrieval instead of IEnumarable

在该帖子中,Microsoft建议采用以下解决方法:

相反,我们建议您对Single()和First()使用Take(1).AsEnumerable()然后使用.First()或.Single()或.FirstOrDefault()。 Take(1)被翻译为SELECT TOP 1并在服务器端处理,因此比之前的建议更有效,并且是您正在尝试实现的目标。

通过包含Take(1)语句,只有第一个结果将被加载到内存中而不是where子句的整个结果中。

在您的代码中,这将转换为以下内容:

var query = client.CreateDocumentQuery<Cliente>(
               UriFactory.CreateDocumentCollectionUri(databaseId, colletionId), queryOptions)
             .Where(x => x.Email == email || x.Cpf == cpf)
             .Take(1)
             .AsEnumerable()
             .FirstOrDefault();

正如其他人所提到的,不要忘记将您的退货类型更新为Cliente


1
投票

你必须做这样的事情:

public Cliente GetByEmailCpf(string email, string cpf, string colletionId) {
  FeedOptions queryOptions = new FeedOptions {
   MaxItemCount = -1
  };

  IQueryable <Cliente> cliente = client.CreateDocumentQuery <Cliente> (
    UriFactory.CreateDocumentCollectionUri(databaseId, colletionId), queryOptions)
   .Where(x => x.Email == email || x.Cpf == cpf).ToList().FirstOrDefault();

  return cliente;
 }

但是在较大的集合中,不建议这样做。建议您使用异步页面对结果进行分页。

public async Task<Cliente> GetByEmailCpf(string email, string cpf, string colletionId) {
  FeedOptions queryOptions = new FeedOptions {
   MaxItemCount = -1
  };

  var query = client.CreateDocumentQuery <Cliente> (
    UriFactory.CreateDocumentCollectionUri(databaseId, colletionId), queryOptions)
   .Where(x => x.Email == email || x.Cpf == cpf).AsDocumentQuery();

  while (query.HasMoreResults)
  {
      var items = await query.ExecuteNextAsync<Cliente>();
      if(items.Count > 0)
          return items.FirstOrDefault();
  }

  return null;
 }

0
投票

如果您只想从集合中检索单个文档,则需要将方法返回类型更改为Cliente而不是IQueryable <Cliente>

public Cliente GetByEmailCpf(string email, string cpf, string colletionId)
{
    FeedOptions queryOptions = new FeedOptions
    {
        MaxItemCount = -1
    };

    var query = client.CreateDocumentQuery<Cliente>(
              UriFactory.CreateDocumentCollectionUri(databaseId, colletionId), queryOptions)
             .Where(x => x.Email == email || x.Cpf == cpf);

    //If your collection have more than one document of specific email and cpf then
    Cliente cliente = query.ToList().FirstOrDefault();

    //If your collection have only single document of specific email and cpf then
    Cliente cliente = query.ToList().SingleOrDefault();


    return cliente;
}

尝试一次它可以帮助你。


0
投票

我以前有这个扩展:

public static T TakeOne<T>(this IQueryable<T> source)
{
    var documentQuery = source.AsDocumentQuery();            
    if (documentQuery.HasMoreResults)
    {
        var queryResult = documentQuery.ExecuteNextAsync<T>().Result;
        if (queryResult.Any())
        {
            return queryResult.Single<T>();
        }
    }
    return default(T);
}

然后你可以这样做:

Cliente cliente = client.CreateDocumentQuery <Cliente> (
    UriFactory.CreateDocumentCollectionUri(databaseId, colletionId), queryOptions)
   .Where(x => x.Email == email || x.Cpf == cpf).TakeOne();
© www.soinside.com 2019 - 2024. All rights reserved.