如何为计数和by子句动态创建Expression <Func <>> 更新

问题描述

我需要为以下查询创建动态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);

但是要获取CountGroup By条款,应如何做。

解决方法

我不熟悉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 已经为您翻译了所有查询,因此,除非我不知道,否则您将自己通过将表达式映射到查询来编写不必要的且优化程度可能较低的实现。

,

我相信您可以为此使用动态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)");
,

CountGroupBy是方法。因此,您首先需要使用反射来获取相应的MethodInfo(请注意从Queryable类(而不是Enumerable类中获取方法,以及正确的重载!)。

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


更新

但是,如果我正确理解了您的动机,那么您实际上是在根据从City得到的基数IQueryable来动态构建一个{-{1}},其中有子句,选择,分组依据和/或计数。库,对吗?

在这种情况下,您不应IQueryableCount表示为表达式。相反,您应该在基础GroupBy上动态调用 real 方法WhereSelectCountGroupBy(以获取另一个IQueryable),但会动态为这些方法的参数构建lambda表达式。最后,您将获得IQueryable,Cosmos DB LINQ提供程序可以对其进行评估。