简体   繁体   English

解决通用lambda表达式类型

[英]Resolving generic lambda expression type

I have a method that calls Entity Framework functions. 我有一个调用实体框架函数的方法。 It is responsible for sending the "select clause", "order by clause" and possible includes (considering that I'm using lazy loading). 它负责发送“ select子句”,“ order by子句”,并且可能包含(考虑到我正在使用延迟加载)。 The method looks like this: 该方法如下所示:

public IEnumerable<TReturn> GetAll<TReturn, TOrderKey>(
    Expression<Func<TEntity, TReturn>> selectExp,
    Expression<Func<TEntity, TOrderKey>> orderbyExp,
    Boolean descending,
    params Expression<Func<TEntity, Object>>[] includeExps)
{
       var query = DbSet.AsQueryable();
       query = !descending ? query.OrderBy(orderByExp) : query.OrderByDescending(orderByExp);
       if (includeExps != null)
          query = includeExps.Aggregate(query, (current, exp) => current.Include(exp));
       return query.Select(selectExp).ToList();
}

When I call: 当我打电话时:

_service.GetAll(i => new { i.Name}, i => i.Name, false, null);

It works fine! 工作正常! That is the generated SQL is the exactly as I wanted. 那就是生成的SQL正是我想要的。

However, considering a real scenario (in my case I'm using asp.net mvc), I have an Action method that gets the order parameter from the client. 但是,考虑到实际情况(在我的情况下,我使用的是asp.net mvc),我有一个Action方法,该方法从客户端获取order参数。

That is the method: 那是方法:

public JsonResult GetAllUsers(string sortColumn, bool sortDescending)
{
    //sortColumn string must be translated in a Expression
    var users = _service.GetAll(i => new { i.Name, i.Email }, i => i.Name, sortDescending, null);
    //
    //
}

My first attempt was to create an expression for every column, like this: 我的第一个尝试是为每个列创建一个表达式,如下所示:

public JsonResult GetAllUsers(string sortColumn, bool sortDescending)
    {
        //I don't what is the Type that I should put here
        //It can be anything, like: Expression<Func<User, String>>,
        //Expression<Func<User, Guid>>, Expression<Func<User, Int>>
        ?Type? orderExp;
        switch(sortColumn)
        {
             case "UserId":
                 //Expression<Func<User, Guid>> 
                 orderExp = i => i.UserId; 
                 break;
            case "Name":
                 //Expression<Func<User, String>> 
                 orderExp = i => i.Email; 
                 break;
        }
        //sortColumn string must be translated in a Expression
        var users = _service.GetAll(i => new { i.Name, i.Email }, orderExp, sortDescending, null);
        //
        //
    }

I want to create an expression based on sortProperty, there's a lot of information about it over the stackoverflow, however (see the action method) the variable must be typed before the process. 我想创建一个基于sortProperty的表达式,在stackoverflow上有很多关于它的信息,但是(请参阅操作方法)必须在处理之前键入变量。 The GetAll method can't be called inside every "case" because it returns an anonymous type. 不能在每个“ case”内部调用GetAll方法,因为它返回匿名类型。

I can't convert all columns to Expression<Func<User, Object>> because entity framework does not support it. 我不能将所有列都转换为Expression<Func<User, Object>>因为实体框架不支持它。

Linq.Dynamic should help, but I don't want to use string parameters. Linq.Dynamic应该有所帮助,但我不想使用字符串参数。

You could overload your GetAll method as follows: 您可以按如下方式重载GetAll方法:

public IEnumerable<TReturn> GetAll<TReturn>(
    Expression<Func<TEntity, TReturn>> selectExp,
    string orderColumnName,
    Boolean descending,
    params Expression<Func<TEntity, Object>>[] includeExps)
{
    var entityType = typeof(TEntity);
    var prop = entityType.GetProperty(orderColumnName);
    var param = Expression.Parameter(entityType, "i");
    var orderExp = Expression.Lambda(
        Expression.MakeMemberAccess(param, prop), param);

    // get the original GetAll method overload
    var method = this.GetType().GetMethods().Where(m => m.Name == "GetAll" && m.GetGenericArguments().Length == 2);
    var actualMethod = method.First().MakeGenericMethod(typeof(TReturn), prop.PropertyType);
    return (IEnumerable<TReturn>)actualMethod.Invoke(this, new object[] { selectExp, orderExp, descending, includeExps });
}

Just add a few more checks for null values, otherwise invalid sortColumn names will come back haunting you. 只需再添加一些检查以获取null值,否则无效的sortColumn名称将再次困扰您。

Use it similar to your current approach: 使用它的方式类似于您当前的方法:

_service.GetAll(i => new { i.Name, i.Email }, sortColumn, sortDescending, null);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM