LinqExpression 嵌套 属性,与字符串比较
LinqExpression nested property, compare to string
我正在努力实施一种通用模式,以便能够过滤 where 子句。基本用例是我们的 API 接受一个名为 ?filterBy:AddressState:VA
的查询参数。
我正在尝试创建能够将子句普遍附加到 IQueryable
的东西。基本上每个 API 都需要创建一个键/Expressions
的字典,它将查找 属性 以比较 filterBy
的右侧,例如VA
.. 这是我到目前为止所拥有的,但它目前因错误
而崩溃
"The binary operator Equal is not defined for the types 'System.Func`2[Framework.Models.User,System.String]' and 'System.String'.",
示例字典:
public Dictionary<string, Expression<Func<User, Object>>> FILTER_BY = new Dictionary<string, Expression<Func<User, Object>>>()
{
{ "addressstate", (x) => x.Address.State},
};
调用扩展方法:
baseQ = baseQ.FilterBy(filterBy, FILTER_BY);
扩展方法:
public static string GetPropertySymbol<T, TResult>(this Expression<Func<T, TResult>> expression)
{
return String.Join(".",
((MemberExpression)expression.Body).GetMembersOnPath()
.Select(m => m.Member.Name)
.Reverse());
}
将嵌套 select 转换为强
的辅助方法
static Expression CreateExpression(Type type, string propertyName)
{
var param = Expression.Parameter(type, "x");
Expression body = param;
foreach (var member in propertyName.Split('.'))
{
body = Expression.PropertyOrField(body, member);
}
return Expression.Lambda(body, param);
}
被破坏的实用功能。
public static IQueryable<T> FilterBy<T, TProperty>(this IQueryable<T> query, string filterBy, Dictionary<string, Expression<Func<T, TProperty>>> filterExpressions)
{
if (!string.IsNullOrEmpty(filterBy))
{
//parse on ':' throw argument if there is not two.
var split = filterBy.Split(':');
var key = split[0];
var right = string.Join("", split.Skip(1));
var expression =filterExpressions.FirstOrDefault(x=>x.Key == key.ToLower());
if (expression.Key != null)
{
var parameterItem = Expression.Parameter(typeof(T), "item");
var rightExp = Expression.Constant(right);
var left = CreateExpression(typeof(T),expression.Value.GetPropertySymbol());
var lambda = Expression.Lambda<Func<T, bool>>(
Expression.Equal(
left,
rightExp
),
parameterItem
);
return query.Where(lambda);
}
}
return query;
}
一旦我进行了基本的字符串比较,我实际上可能会了解其他类型的常量字符串、整数、日期时间。但我可以通过字符串短期获得。
如果您有任何其他问题,请告诉我。我尝试了一种不同的方法,我尝试包装现有的基本上称为 Invoke 的函数,然后生成一个新函数,但它导致 entity framework 抛出关于 .Invoke 不受支持的异常。
这个方法
static Expression CreateExpression(Type type, string propertyName)
创建一个单独的参数。您需要修改它以接收参数作为参数和 return 只是主体(而不是 lambda),所以这里
var left = CreateExpression(typeof(T),expression.Value.GetPropertySymbol());
你可以这样称呼它
var left = CreateExpression(parameterItem,expression.Value.GetPropertySymbol());
修改后的函数可以这样
static Expression CreateExpression(ParameterExpression param, string propertyName)
{
Expression body = param;
foreach (var member in propertyName.Split('.'))
{
body = Expression.PropertyOrField(body, member);
}
return body;
}
或简单
static Expression CreateExpression(Expression target, string memberPath)
{
return memberPath.Split('.').Aggregate(target, Expression.PropertyOrField);
}
我正在努力实施一种通用模式,以便能够过滤 where 子句。基本用例是我们的 API 接受一个名为 ?filterBy:AddressState:VA
的查询参数。
我正在尝试创建能够将子句普遍附加到 IQueryable
的东西。基本上每个 API 都需要创建一个键/Expressions
的字典,它将查找 属性 以比较 filterBy
的右侧,例如VA
.. 这是我到目前为止所拥有的,但它目前因错误
"The binary operator Equal is not defined for the types 'System.Func`2[Framework.Models.User,System.String]' and 'System.String'.",
示例字典:
public Dictionary<string, Expression<Func<User, Object>>> FILTER_BY = new Dictionary<string, Expression<Func<User, Object>>>()
{
{ "addressstate", (x) => x.Address.State},
};
调用扩展方法:
baseQ = baseQ.FilterBy(filterBy, FILTER_BY);
扩展方法:
public static string GetPropertySymbol<T, TResult>(this Expression<Func<T, TResult>> expression)
{
return String.Join(".",
((MemberExpression)expression.Body).GetMembersOnPath()
.Select(m => m.Member.Name)
.Reverse());
}
将嵌套 select 转换为强
的辅助方法 static Expression CreateExpression(Type type, string propertyName)
{
var param = Expression.Parameter(type, "x");
Expression body = param;
foreach (var member in propertyName.Split('.'))
{
body = Expression.PropertyOrField(body, member);
}
return Expression.Lambda(body, param);
}
被破坏的实用功能。
public static IQueryable<T> FilterBy<T, TProperty>(this IQueryable<T> query, string filterBy, Dictionary<string, Expression<Func<T, TProperty>>> filterExpressions)
{
if (!string.IsNullOrEmpty(filterBy))
{
//parse on ':' throw argument if there is not two.
var split = filterBy.Split(':');
var key = split[0];
var right = string.Join("", split.Skip(1));
var expression =filterExpressions.FirstOrDefault(x=>x.Key == key.ToLower());
if (expression.Key != null)
{
var parameterItem = Expression.Parameter(typeof(T), "item");
var rightExp = Expression.Constant(right);
var left = CreateExpression(typeof(T),expression.Value.GetPropertySymbol());
var lambda = Expression.Lambda<Func<T, bool>>(
Expression.Equal(
left,
rightExp
),
parameterItem
);
return query.Where(lambda);
}
}
return query;
}
一旦我进行了基本的字符串比较,我实际上可能会了解其他类型的常量字符串、整数、日期时间。但我可以通过字符串短期获得。
如果您有任何其他问题,请告诉我。我尝试了一种不同的方法,我尝试包装现有的基本上称为 Invoke 的函数,然后生成一个新函数,但它导致 entity framework 抛出关于 .Invoke 不受支持的异常。
这个方法
static Expression CreateExpression(Type type, string propertyName)
创建一个单独的参数。您需要修改它以接收参数作为参数和 return 只是主体(而不是 lambda),所以这里
var left = CreateExpression(typeof(T),expression.Value.GetPropertySymbol());
你可以这样称呼它
var left = CreateExpression(parameterItem,expression.Value.GetPropertySymbol());
修改后的函数可以这样
static Expression CreateExpression(ParameterExpression param, string propertyName)
{
Expression body = param;
foreach (var member in propertyName.Split('.'))
{
body = Expression.PropertyOrField(body, member);
}
return body;
}
或简单
static Expression CreateExpression(Expression target, string memberPath)
{
return memberPath.Split('.').Aggregate(target, Expression.PropertyOrField);
}