我有表达式助手类,用于服务器端过滤我动态检查的列名,例如:
public static Expression<Func<TItem, bool>> PropertyContains<TItem>(PropertyInfo propertyInfo, string value)
{
var param = Expression.Parameter(typeof(TItem));
var m = Expression.MakeMemberAccess(param, propertyInfo);
var c = Expression.Constant(value, typeof(string));
var mi = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
var body = Expression.Call(m, mi, c);
return Expression.Lambda<Func<TItem, bool>>(body, param);
}
这个工作得很好。我还有另一个静态辅助方法来比较值是否相等:
public static Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(
PropertyInfo property, TValue value)
{
var param = Expression.Parameter(typeof(TItem));
var xx = Expression.Property(param, property);
var body = Expression.Equal(Expression.Property(param, property),
Expression.Constant(value));
return Expression.Lambda<Func<TItem, bool>>(body, param);
}
这也很好用。
但是,对于小数字段(Decimal(19,4)在 SQL 中),我遇到的问题是,用户只能在 UI 上看到 2 位数字作为小数位让我们说 $19.32 所以当他们在搜索字段中输入 19.32 时,它与作为记录的 db 记录不匹配在 db 中实际上是 19.3224 可以说。数学上如此19.32 != 19.3224,但由于我在 UI 上只显示 2 个小数位,它不会返回用户正在寻找的记录。
我的问题是,我不确定如何在 Expression 中操作 db 记录的值。甚至现在使用 Decimal.Truncate 就足够了(这意味着如果我忽略小数位并只比较 int 部分就可以了)
我尝试了如下方法:
public static Expression<Func<TItem, bool>> PropertyEqualMoneyFields<TItem>(PropertyInfo propertyInfo, decimal value)
{
var param = Expression.Parameter(typeof(TItem));
var m = Expression.MakeMemberAccess(param, propertyInfo);
var c = Expression.Constant(value, typeof(decimal));
var mi = typeof(decimal).GetMethod("Truncate", new Type[] { typeof(decimal) });
var body = Expression.Call(m, mi, c);
return Expression.Lambda<Func<TItem, bool>>(body, param);
}
我称之为:
string filteredColumnNameInDb = "SomeMoneyColumnName"; // coming from ui actually
PropertyInfo filteredProperty = typeof(SomeDto).GetProperty(filteredColumnNameInDb);
query = query.Where(ExpressionHelper.PropertyEqualMoneyFields<SomeDto>filteredProperty,decimal.Truncate(decimalValue)));
但它会抛出一个异常Static method requires null instance, non-static method requires non-null instance.,即使没有异常,这也不会起作用,因为我仍然需要Expression.Equal在某些时候应用来比较它们在截断后是否相等。
如果我完全不采用这种方法,我很想听听任何其他方法来做到这一点。
或者,如果不清楚,如果有人可以指出“在进行任何比较之前在 db 记录上运行 sql 函数”,那将非常有用,所以也许我会创建一些 sql 函数先应用于该记录,然后进行Expression.Equal比较。
PS:我知道我可以在 ToList() 之后轻松做到这一点,但这是服务器端过滤的重点,因为我不想加载整个数据集!