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

时间:2018-09-20 13:38:15

标签: c# linq azure-cosmosdb

如何更改我的方法以仅返回类型为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   ==值(LR.Mobile.Data.Repositories.ModuloProduto.Classes.ClienteRepository + <> c__DisplayClass5_0)。电子邮件)   OrElse(x.Cpf ==   value(LR.Mobile.Data.Repositories.ModuloProduto.Classes.ClienteRepository + <> c__DisplayClass5_0).cpf)))。FirstOrDefault()   不被支持。支持的表达式为“ Queryable.Where”,   “ Queryable.Select”和“ Queryable.SelectMany”

4 个答案:

答案 0 :(得分:2)

如您的错误所述,您似乎正在尝试使用FirstOrDefault。目前尚不支持此功能,并且根据Azure Cosmos反馈网站,当前还没有将其优先考虑:

Add support for single entity retrieval instead of IEnumarable

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

  

相反,我们建议您使用Take(1).AsEnumerable(),然后对Single()和First()使用.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 :(得分: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;
 }

答案 2 :(得分: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;
}

尝试一次,可能对您有帮助。

答案 3 :(得分: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();