Как динамически создавать Expression <Func <>> для предложения count и group by

Мне нужно создать динамический предикат лямбда-выражения для запроса ниже в 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);

Но для получения Count и для Group By Пункт, как это сделать.

3 ответа

Я не знаком с 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. Возможно, мне не хватает того, что вы пытаетесь сделать, но я не вижу никаких преимуществ в использовании здесь деревьев выражений.

IQueryProvider<> CosmoDB уже переводит для вас все запросы, поэтому, если я чего-то не знаю, вы пишете ненужные и, возможно, менее оптимизированные реализации, самостоятельно сопоставляя выражения с запросами.

Я считаю, что для этого можно использовать динамический Linq:


Существует расширение GroupBy, которое принимает строку:https://dynamic-linq.net/basic-query-operators

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)");

Count а также GroupByметоды. Итак, сначала нужно получить соответствующийMethodInfos с помощью отражения (позаботьтесь о том, чтобы получить методы из Queryable класс, а не Enumerable, и правильная перегрузка!).

Затем создайте выражение вызова метода, используя Expression.Call(null, methodInfo, queryable). (Первый параметр должен бытьnull поскольку оба метода статичны.) Здесь queryable это IQueryable вы уже достигли этого момента, на котором вы хотите позвонить Count или GroupByсоответственно. ЗаGroupBy, вам также необходимо добавить дополнительный параметр, который является лямбда-выражением для проецирования City собственность - я полагаю, вы знаете, как это построить.


Обновить

Но если я правильно понимаю вашу мотивацию, вы на самом деле пытаетесь динамически построить IQueryable с предложениями where, select, groupby и / или counts на основе базы IQueryable вы получаете из библиотеки, это правильно?

В этом случае не следует выражатьCount а также GroupByкак выражения. Скорее вы должны динамически вызывать реальные методыWhere, Select, Count а также GroupBy на твоей базе IQueryable (чтобы получить другой IQueryable), но динамически строить лямбда-выражения для параметров этих методов. В итоге у вас будетIQueryable которую может оценить поставщик LINQ Cosmos DB.

Другие вопросы по тегам