【问题标题】:How do I use Generics to create multiple/nested SelectMany joins in Linq for DocumentDB如何使用泛型在 Linq for DocumentDB 中创建多个/嵌套 SelectMany 联接
【发布时间】:2018-06-09 11:25:44
【问题描述】:

我正在尝试向 Document Db 的通用存储库添加一个方法。

我希望它生成与此类似的 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"))

但我得到了错误:

输入集名称或别名“tmp”在 FROM 子句。

是否可以使用泛型创建类似的东西,我们如何为“tmp”指定不同的值。或者这不是正确的方法?

【问题讨论】:

  • 你的条件表达式是什么样的?它是自动生成的吗?
  • 不,这是在需要的地方编码的。此示例编译但有运行时错误:approval = await _approvals.SelectManyAsync(ownerQuery,approval =>approval.Versions,version => version.ApprovalGroups,approvalGroups =>approvalGroups.Users,批准用户查询);
  • 主要问题是尝试使用 predicateBuilder 和多个 SelectMany 构建查询,以传递给一个通用方法,该方法将获得过滤、排序、调整的列表。
  • 我有一个使用动态创建的带参数的 sql 语句的解决方法,但更喜欢使用 Linq 来获得更通用的解决方案。

标签: c# linq azure generics azure-cosmosdb


【解决方案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)))));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多