У меня есть класс помощника по выражениям, который я использую для фильтрации на стороне сервера для имен столбцов, которые я проверяю динамически, таких как:
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);
}
Этот работает отлично. У меня также есть другой вспомогательный метод stati c для сравнения, если значения равны:
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) проблема, с которой я сталкиваюсь, заключается в том, что пользователь видит только 2 цифры как десятичное место в пользовательском интерфейсе, скажем, $ 19,32. Поэтому, когда они вводят 19,32 в поле поиска , он не совпадает с записью в БД, поскольку запись в БД на самом деле 19.3224, скажем так. Математически 19.32 != 19.3224
, но, поскольку я показываю только 2 знака после запятой в пользовательском интерфейсе, он не возвращает искомый пользователь записи.
Моя проблема в том, что я не уверен, как манипулировать значением записи в базе данных в выражении. Или даже использования 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
в какой-то момент для сравнения, если они равны после усечения.
Если я полностью ухожу с дороги при таком подходе, я хотел бы услышать любой другой способ сделать это.
Или, если это неясно, было бы очень полезно, если бы кто-то мог укажите на «запуск функции sql для записи в БД перед выполнением какого-либо сравнения», поэтому, возможно, я бы создал некоторую функцию sql, чтобы сначала применить ее к этой записи, а затем выполните сравнение Expression.Equal
.
PS: я знаю, что могу легко сделать это после ToList (), но в этом весь смысл фильтрации на стороне сервера, поскольку я НЕ хочу загружать весь набор данных!