如何使用Generics在Linq for DocumentDB中创建多个/嵌套的SelectMany连接

时间:2018-06-09 11:25:45

标签: c# linq azure generics azure-cosmosdb

我正在尝试将方法添加到Document Db的Generic Repository。

我希望它生成类似于此(但通用)的SQL:

SELECT VALUE c FROM c
JOIN versions IN c["versions"] 
JOIN groups IN versions["userGroups"] 
JOIN users IN groups["users"] 
WHERE c.type = "Approval" and users["userId"] = "xxx"

我试过这个......

public async Task<ListResult<TResult>> SelectManyAsync<TEntity1, TEntity2, TEntity3, TEntity4, TResult>(Expression<Func<TEntity1, bool>> condition01, Expression<Func<TEntity1, IEnumerable<TEntity2>>> condition02, Expression<Func<TEntity2, IEnumerable<TEntity3>>> condition03, Expression<Func<TEntity3, IEnumerable<TEntity4>>> condition04, Expression<Func<TEntity4, bool>> condition05) where TEntity1:class
        {
            var feedOptions = GetFeedOptions();

            var query = DocumentDbContext.Client.CreateDocumentQuery<TEntity1>(DocumentDbContext.DocumentCollection.DocumentsLink, feedOptions)
                .Where(condition01)
                .SelectMany(condition02)
                .SelectMany(condition03)
                .SelectMany(condition04)
                .Where(condition05)
                .AsDocumentQuery();

// .. removed code for brevity

}

导致类似这样的事情:

SELECT VALUE tmp FROM root 
JOIN tmp IN root["versions"] 
JOIN tmp IN tmp["userGroups"] 
WHERE (true AND (tmp["userId"] = "xxx"))

但是我收到了错误:

  

输入集名称或别名&#39; tmp&#39;在。中指定了多次   FROM子句。

是否可以使用泛型创建这样的东西,我们如何为&#34; tmp&#34;指定不同的值。或者这不是正确的方法吗?

1 个答案:

答案 0 :(得分:1)

不确定是否存在此错误,此类查询错误无法正常工作。您需要使用嵌套的selectMany。

以下示例应该有效:

public async Task<IEnumerable<TRes>> Query<T, TRes>(
        string docCollection,
        string partitionKey,
        Func<IOrderedQueryable<T>, IQueryable<TRes>> func,
        string continuationToken = null)
    {
        var queryable =
            CosmosClient.CreateDocumentQuery<T>(
                CollectionUri(docCollection),
                new FeedOptions
                {
                    MaxItemCount = 100,
                    RequestContinuation = continuationToken,
                    EnableCrossPartitionQuery = false,
                    PartitionKey = new PartitionKey(partitionKey),
                    PopulateQueryMetrics = true,
                });

        return await func(queryable).AsDocumentQuery().ExecuteNextAsync<TRes>();
    }


await Query<Doc, string>("collection", "pk",
            (IOrderedQueryable<Doc> x) => x.SelectMany(p => p.Versions.SelectMany(d => d.UserGroups.SelectMany(k => k.Users.Select(u => u.Name)))));