0

我需要为以下查询创建动态 lambda 表达式谓词以在 Cosmos DB 中查询。

*select City, COUNT(City) as CityCount FROM Cities where status="Active"
group by City*

早些时候我已经为这样的平等操作创建了

var parameter = Expression.Parameter(typeof(T), "t");

MemberExpression expBody = Expression.Property(parameter, columnName);

但是对于 getCount和 for Group ByClause 如何做到这一点。

4

3 回答 3

1

我不熟悉 CosmoDB,但是 LINQ 不会更容易吗?

IQueryable<City> query 
    = cityContainer.GetItemLinqQueryable<City>()
                   .Where(city => city.Status == "Active")
                   .GroupBy(city => city);

using FeedIterator<City> iterator = query.ToFeedIterator<City>();

int cityCount = 0;

for (;iterator.HasMoreResults; cityCount++)
{
    City city = await setIterator.ReadNextAsync();
                    
    // do stuff
}

编辑:

我在评论中的回答示例->

struct City
{
    public string Name { get; set; }
    public int Population { get; set; }
}

IQueryable<City> cities = default;

Func<City, bool> HasNastyName = c => c.Name.Length > 25;
Func<City, bool> IsMassive = c => c.Population > 500;

var nastyNameCities = cities.Where(HasNastyName);
var massiveCities   = cities.Where(IsMassive);

考虑到一般构建这些的附加选项,您可以使用 LINQ 非常动态地构建谓词。我可能会错过您正在尝试做的事情,但我看不到在这里使用表达式树有任何优势。

CosmoDB 的 IQueryProvider<> 已经为您翻译了所有查询,因此除非我不知道某些事情,否则您通过自己将表达式映射到查询来编写不必要且可能不太优化的实现。

于 2020-08-13T10:47:37.433 回答
0

我相信您可以为此使用动态 Linq:


有一个采用字符串的 GroupBy 扩展: https ://dynamic-linq.net/basic-query-operators#GroupBy

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;

namespace ConsoleApp7
{
    class Program
    {
        static void Main(string[] args)
        {
            IQueryable<MyOb> testData = new EnumerableQuery<MyOb>(new List<MyOb>());
            var query = testData
                .Where(o => o.Active)
                .GroupBy("City")
                .Select("new (Key as City, Count() as CityCount)");

            Console.WriteLine("Hello World!");
        }
    }

    public class MyOb
    {
        public string City { get; set; }
        public bool Active { get; set; }
    }
}

Dynamic Linq 的文档提供了这个例子

var result = context.Posts.GroupBy("BlogId").Select("new(Key, Count() AS Count)");
于 2020-08-13T11:41:23.607 回答
0

Count并且GroupBy是方法。所以你首先需要MethodInfo使用反射来获取对应的 s (注意从Queryable类中获取方法,notEnumerable和正确的重载!)。

然后使用创建一个方法调用表达式Expression.Call(null, methodInfo, queryable)。(第一个参数应该是null因为这两个方法都是静态的。)在这里,queryableIQueryable已经建立了要分别调用CountGroupBy的点。对于GroupBy,您还需要添加一个额外的参数,它是用于投影City属性的 lambda 表达式 - 我假设您知道如何构建它。


更新

但是,如果我正确理解您的动机,您实际上是在尝试根据您从库中获得IQueryable的基础动态地构建一个带有 where 子句、选择、groupby 和/或计数的方法,对吗?IQueryable

在这种情况下,您不应该将Countand表达GroupBy为表达式。相反,您应该在您的基础上动态调用真实方法 、 和(获取Where另一个Select),但为这些方法的参数动态构建 lambda 表达式。最后,您将获得Cosmos DB LINQ 提供程序可以评估的一个。CountGroupByIQueryableIQueryableIQueryable

于 2020-08-24T19:46:40.340 回答