使用表达式和字典的列映射

时间:2018-07-19 05:26:12

标签: c# entity-framework-core expression-trees iqueryable linq-expressions

我在为IQueryable对象编码表达式时遇到麻烦。我想不出使用表达式将字符串映射到对象属性的正确方法。

这是我的查询对象和映射字典:

var query = context.Industries.AsQueryable();
var columnsMap = new Dictionary<string, Expression<Func<Industry, object>>>()
            {
                ["name"] = v => v.Name,
                ["isicCode"] = v => v.IsicCode.Data,
                ["isicCodeTitle"] = v => v.IsicCode.Title,
                ["isActive"] = v => v.IsActive,
            };

并且我正在使用columnsMap字典在扩展类中将Orderby应用于查询:

public static IQueryable<T> ApplyOrdering<T>(this IQueryable<T> query, IQueryObject queryObj, Dictionary<string, Expression<Func<T, object>>> columnsMap)
{
    if (String.IsNullOrWhiteSpace(queryObj.SortBy) || !columnsMap.ContainsKey(queryObj.SortBy))
        return query;
    if (queryObj.IsSortAsc)
        return query.OrderBy(columnsMap[queryObj.SortBy]);
    else
        return query.OrderByDescending(columnsMap[queryObj.SortBy]);
}

OrderBy可以,但是我需要对ApplyFiltering做同样的事情,但是要过滤IQueryable对象,我需要使用不同的表达式来表示where方法Expression<Func<T, bool>>

public static IQueryable<T> ApplyFiltering<T>(this IQueryable<T> query, IQueryObject queryObj, Dictionary<string, Expression<Func<T, object>>> columnsMap)
{           
    query.Where(columnsMap['name'] == "test Name"); //this is the problem. 
    return query;
}

问题是如何在ApplyFiltering方法中使用我的columnMap?还是应该为此更改我的columnMap?

1 个答案:

答案 0 :(得分:2)

这很简单。唯一的问题是,当您有一个值类型列(例如intboolDateTime时)... Expression<Func<Industry, object>>将对我们必须删除的object的字段/属性。 string不存在此问题。

// isActive is a bool
Expression<Func<Industry, object>> exp = columnsMap["isActive"];
object value = true; // You can't use "true" (string) here! isActive is a bool

// Other exammple
// Expression<Func<Industry, object>> exp = columnsMap["name"];
// object value = "Foo";

var body = exp.Body;

// Remove the boxing for value types
if (body.NodeType == ExpressionType.Convert)
{
    body = ((UnaryExpression)body).Operand;
}

var eq = Expression.Equal(body, Expression.Constant(value, body.Type));

var exp2 = Expression.Lambda<Func<T, bool>>(eq, exp.Parameters);

return query.Where(exp2);

使用string value的示例:

Expression<Func<Industry, object>> exp = columnsMap["isActive"];
string value = "true";
// Other exammple
//Expression<Func<Industry, object>> exp = columnsMap["name"];
//string value = "Foo";

var body = exp.Body;

// Remove the boxing for value types
if (body.NodeType == ExpressionType.Convert)
{
    body = ((UnaryExpression)body).Operand;
}

object value2 = value;

if (value2 != null && body.Type != value2.GetType())
{
    value2 = Convert.ChangeType(value2, body.Type);
}

var eq = Expression.Equal(body, Expression.Constant(value2, body.Type));

var exp2 = Expression.Lambda<Func<Industry, bool>>(eq, exp.Parameters);

return query.Where(exp2);