Azure DocumentDb错误 "查询必须评估为IEnumerable"

15

我试图查询我的Azure DocumentDb存储账户以尝试检索单个记录,但遇到了问题。这是我的WebAPI代码:

// Controller...
public AccountController : ApiController {
    // other actions...

    [HttpGet]
    [Route("Profile")]
    public HttpResponseMessage Profile()
    {
        var userId = User.Identity.GetUserId();
        var rep = new DocumentRepository<UserDetail>();
        var profile = rep.FindById(userId);

        if (profile == null)
            return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Profile not found");

        return Request.CreateResponse(HttpStatusCode.OK, profile);
    }
}

// Repository
public class DocumentRepository<TEntity> : IDocumentRepository<TEntity> where TEntity : IIdentifiableEntity
{
    private static DocumentClient _client;
    private static string _databaseName;
    private static string _documentsLink;
    private static string _selfLink;

    public DocumentRepository()
    {
        _client = new DocumentClient(new Uri(ConfigurationManager.AppSettings["DocumentDbEndpointUrl"]), ConfigurationManager.AppSettings["DocumentDbAuthKey"]);
        _databaseName = ConfigurationManager.AppSettings["DocumentDbDatabaseName"];
        var _database = ReadOrCreateDatabase();

        var collection = InitialiseCollection(_database.SelfLink, EntityName);
        _documentsLink = collection.DocumentsLink;
        _selfLink = collection.SelfLink;
    }

    // other methods...

    public TEntity FindById(string id)
    {
        return _client.CreateDocumentQuery<TEntity>(_documentsLink).SingleOrDefault(u => u.Id.ToString() == id);
    }
}

这个FindById方法导致了以下问题:

'Microsoft.Azure.Documents.Linq.DocumentQueryException'类型的异常在Microsoft.Azure.Documents.Client.dll中发生,但未在用户代码中处理

附加信息:查询表达式无效,表达式返回类型Foo.Models.DocumentDbEntities.UserDetail不受支持。查询必须评估为IEnumerable。

我不理解这个错误是什么意思,也不知道该如何修复它。我不想返回IEnumerable或其任何子类,因为此方法将返回01条记录。如果我删除SingleOrDefault子句并将返回类型更改为IQueryable,则可以正常工作,但这不是我想要的。

2个回答

30

SingleOrDefault()在LINQ提供程序中尚不受支持。

将其更改为.Where(u => u.Id.ToString() == id).AsEnumberable().FirstOrDefault();


嗯。这个问题早上时还正常,但现在我需要在 Where 前面使用 AsEnumerable,否则会出错。除此之外没有任何更改。这看起来很奇怪。当前的工作代码是:return Client.CreateDocumentQuery<TEntity>(DocumentsLink).AsEnumerable().Where(u => u.Id.ToString() == id).FirstOrDefault(); 这不理想,因为会对请求方造成检索所有集合并过滤的性能影响。 - Rory McCrossan
确实很奇怪。你绝对不想在Where之前加上AsEnumerable。如果按照我上面的方式放置,会出现什么错误? - Ryan CrawCour
6
有没有关于 Linq Provider 支持哪些 Linq 语句的文档? - Madu Alikor
值得一提的是,在调用AsEnumerable()之后,没有必要更改为FirstOrDefault()。SingleOrDefault()仍然有效,如果这是预期的行为,则应使用它。 - disco
2
AsEnumberable中有一个拼写错误。它应该是AsEnumerable。作为一个懒惰的开发者,我在复制和粘贴时注意到了这一点。 - Siva Kandaraj

1
我无法说为什么 Ryan 的语法对你不起作用,但是你应该能够通过使用带有显式定义查询字符串的 CreateDocumentQuery<>() 重载来避免额外的性能损失,而不是使用 .Where()。请注意保留 HTML 标签。
string query = string.Format("SELECT * FROM docs WHERE docs.id = \"{0}\"", id);
return _client.CreateDocumentQuery<TEntity>(DocumentsLink, query).AsEnumerable().FirstOrDefault();

你可能需要对查询进行一些调整,但那种形式的查询应该可以工作。

谢谢您的回答。我后来发现问题是因为我正在使用Guid,在目前的DocumentDb中与LINQ lambdas存在问题。使用SQL语法进行选择确实可以解决这个问题。Ryan的解决方案最初确实有效,我只能假设这是与LINQ问题有关的问题。 - Rory McCrossan
你是如何将 GUID 转换为字符串的?我认为在 DocumentDB 中,使用 Guid.ToString("N") 比默认的 Guid.ToString() 更好。你可能是对的,这可能是 Linq 查询提供程序中的错误导致的,但尝试使用 .ToString("N") 也许值得一试。 - Andrew Davis
如果您在使用GUID时遇到问题,请确保在NuGet上运行最新的.NET SDK 0.9.1-preview。这个新版本中有一些关于GUID和LINQ的修复。 - Ryan CrawCour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接