C# 如何在运行时创建表达式,以便在具有实体框架的GroupBy()中使用?

C# 如何在运行时创建表达式,以便在具有实体框架的GroupBy()中使用?,c#,entity-framework,lambda,linq-to-entities,C#,Entity Framework,Lambda,Linq To Entities,我正在构建一个新的扩展方法,它将能够动态地对实体框架中的查询结果进行分组 我已经能够使用LinqKit构建动态“where”表达式,但这似乎是另一种动物 新扩展方法的预期用途: var results = entities.GroupBy("someFieldName").ToList(); 扩展方法定义: public static IQueryable<IGrouping<object, TEntity>> GroupBy<TEntity>(

我正在构建一个新的扩展方法,它将能够动态地对实体框架中的查询结果进行分组

我已经能够使用LinqKit构建动态“where”表达式,但这似乎是另一种动物

新扩展方法的预期用途:

var results = entities.GroupBy("someFieldName").ToList();
扩展方法定义:

    public static IQueryable<IGrouping<object, TEntity>> GroupBy<TEntity>(
        this IQueryable<TEntity> source,
        string fieldName) 
        where TEntity : class, IDataEntity
    {
        if (string.IsNullOrEmpty(fieldName))
        {
            return new List<IGrouping<object, TEntity>>().AsQueryable();
        }

        var parameter = Expression.Parameter(typeof(TEntity), "x");
        var fieldXExpression = Expression.Property(parameter, fieldName);
        var lambda = Expression.Lambda<Func<TEntity, object>>(
            Expression.Convert(fieldXExpression, typeof(object)), // throws error when using EF
            parameter);
        return source.AsExpandable().GroupBy(lambda);
    }
是否有一种方法可以在运行时生成适合GroupBy的表达式,该表达式也与EF兼容


感谢您的指导。

不幸的是,您不能在实体框架中按键入为
对象的值进行分组。我认为有两种选择:可以从方法返回
IQueryable
(非泛型)对象,如果要对结果执行数据绑定之类的操作,这将起作用,但对其他许多操作都没有好处。这允许您忽略分组依据的属性类型

public static IQueryable GroupBy<TEntity>(
    IQueryable<TEntity> source,
    string fieldName) 
    where TEntity : class, IDataEntity
{
    if (string.IsNullOrEmpty(fieldName))
    {
        return new List<IGrouping<object, TEntity>>().AsQueryable();
    }

    var parameter = Expression.Parameter(typeof(TEntity), "x");
    var propertyAccess = Expression.Property(parameter, fieldName);
    var lambda = Expression.Lambda(propertyAccess, parameter);

    var groupExpression = Expression.Call(
        typeof(Queryable).GetMethods()
                        .First (x => x.Name == "GroupBy")
                        .MakeGenericMethod(new[]{ typeof(TEntity), propertyAccess.Type }),
        source.Expression,
        lambda);

    var result = source.Provider.CreateQuery(groupExpression);
    return result;
}

通过使用动态Linq,我能够完成我需要的任务。我创建了一个名为ListGroupKeys的扩展方法:

    public static List<object> ListGroupKeys<TEntity>(this IQueryable<TEntity> source, string fieldName)
        where TEntity : class, IDataEntity
    {
        var results = source.GroupBy(fieldName, "it").Select("new (KEY as Group)");

        var list = new List<object>();
        foreach (var result in results)
        {
            var type = result.GetType();
            var prop = type.GetProperty("Group");

            list.Add(prop.GetValue(result));
        }

        return list;
    }
公共静态列表ListGroupKeys(此IQueryable源,字符串字段名)
其中tenty:类,IDataEntity
{
var results=source.GroupBy(fieldName,“it”)。选择(“新建(键为组)”;
var list=新列表();
foreach(结果中的var结果)
{
var type=result.GetType();
var prop=type.GetProperty(“组”);
list.Add(prop.GetValue(result));
}
退货清单;
}

这使我能够获取组键值,以便在后续查询中使用。

Linq to Entities查询提供程序需要知道要按其进行分组的属性的类型;您需要将泛型类型参数添加到方法调用中,您必须显式指定该参数,这可能会首先破坏使用属性名的目的。
public static IQueryable<IGrouping<TProperty,TEntity>> GroupBy<TEntity, TProperty>(
    IQueryable<TEntity> source,
    string fieldName) 
    where TEntity : class, IDataEntity
{
    if (string.IsNullOrEmpty(fieldName))
    {
        return new List<IGrouping<TProperty, TEntity>>().AsQueryable();
    }

    var parameter = Expression.Parameter(typeof(TEntity), "x");
    var propertyAccess = Expression.Property(parameter, fieldName);
    var lambda = Expression.Lambda<Func<TEntity, TProperty>>(propertyAccess, parameter);

    var result = source.GroupBy (lambda);
    return result;
}
    public static List<object> ListGroupKeys<TEntity>(this IQueryable<TEntity> source, string fieldName)
        where TEntity : class, IDataEntity
    {
        var results = source.GroupBy(fieldName, "it").Select("new (KEY as Group)");

        var list = new List<object>();
        foreach (var result in results)
        {
            var type = result.GetType();
            var prop = type.GetProperty("Group");

            list.Add(prop.GetValue(result));
        }

        return list;
    }