Я пытаюсь добавить ToLower() в выражения «Содержит LINQ»: Вот мой код с динамическими выражениями LINQ (содержит):
private static Expression GetExpressionCase<T>(ParameterExpression param, SearchCriteria searchCriteria)
{
MethodInfo containsMethod =
typeof(string).GetMethod("Contains", new[] { typeof(string) });
MemberExpression member =
Expression.Property(param, searchCriteria.Key);
ConstantExpression constant =
Expression.Constant(Convert.ChangeType(searchCriteria.Value, member.Type));
switch (searchCriteria.Operation)
{
case '=':
return Expression.Equal(member, constant);
case '>':
return Expression.GreaterThanOrEqual(member, constant);
case '<':
return Expression.LessThanOrEqual(member, constant);
case ':':
return Expression.Call(member, containsMethod, constant);
}
return null;
}
Мои коды работают нормально, но я хочу добавить ToLower() перед contains(), как этот запрос:
Текущий запрос выглядит следующим образом (только Contains()):
var test = context.Table.Where(x => x.Key.Contains("value"));
Я надеюсь, что запрос будет выглядеть следующим образом (добавлен ToLower()):
var test = context.Table.Where(x => x.Key.ToLower().Contains("hoa"));
Я уже пробовал использовать StringComparison.OrdinalIgnoreCase, но он не может быть переведен поставщиком запросов (postgreSQL).
почему вы создаете выражения, а не просто пишете код? возможно, это часть чего-то большего, но вы можете условно связывать вещи с IQueryable на основе ваших критериев поиска.
@JoelCoehoorn В моем случае postgreSQL не выполняет сравнения без учета регистра. Я знаю, что в Postgre есть ILike, если я прямо запишу запрос, используемый ILike, он работает нормально, но с Contain («ключевое слово», StringComparison.OrdinalIgnoreCase) EF не может его перевести.
fi => fi.DESCRIPTION.ToLower().Contains(description.ToLower())
К сожалению, ОП просит найти способ построить дерево выражений, которое будет представлять написанный вами код, а не сам код.
Также не публикуйте только код ответов. объясните, как работает код и почему он решает проблему ОП.
У вас это хорошо получается, я бы только предложил просто связать результат вызова ToLower
с Contains
.
case ':':
MethodInfo containsMethod =
typeof(string).GetMethod(nameof(string.Contains), new[] { typeof(string) });
MethodInfo toLowerMethod =
typeof(string).GetMethod(nameof(string.ToLower), Type.EmptyTypes);
MethodCallExpression toLowerCall = // X.ToLower();
Expression.Call(member, toLowerMethod, constant);
MethodCallExpression containsCall = // X.Contains(Y);
Expression.Call(toLowerCall, containsMethod, constant);
return containsCall;
Спасибо за ваш ответ, это умный подход, о котором я никогда не думал. К сожалению, он выдает exc: Incorrect number of arguments supplied for call to method 'System.String ToLower()' (Parameter 'method')
когда toLowerCall X.ToLower()
конечно, потому что ToLower
не имеет параметров. Поэтому вместо того, чтобы передавать constant
в качестве последнего параметра, просто опустите его.
Попробуйте следующую реализацию. Я немного упростил это.
private static Expression? GetExpressionCase(ParameterExpression param, SearchCriteria searchCriteria, bool makeLower)
{
Expression memberExpression = Expression.Property(param, searchCriteria.Key);
if (makeLower && memberExpression.Type == typeof(string))
{
memberExpression = Expression.Call(memberExpression, nameof(string.ToLower), Type.EmptyTypes, memberExpression);
}
var searchValue = searchCriteria.Value;
if (makeLower && searchValue is string str)
{
searchValue = str.ToLower();
}
var constant = Expression.Constant(Convert.ChangeType(searchValue, memberExpression.Type));
switch (searchCriteria.Operation)
{
case '=':
return Expression.Equal(memberExpression, constant);
case '>':
return Expression.GreaterThanOrEqual(memberExpression, constant);
case '<':
return Expression.LessThanOrEqual(memberExpression, constant);
case ':':
return Expression.Call(memberExpression, nameof(string.Contains), Type.EmptyTypes, constant);
default:
return null;
}
}
Спасибо, это хорошо работает. Дополнительно: я изменил memberExpression = Expression.Call(memberExpression, nameof(string.ToLower), Type.EmptyTypes, memberExpression);
на memberExpression = Expression.Call(memberExpression, nameof(string.ToLower), Type.EmptyTypes, null);
, чтобы избежать возникновения исключения - неправильное количество аргументов, предоставленных для вызова метода.
SQL-сравнения по умолчанию уже нечувствительны к регистру. И даже если у вас есть нестандартные параметры сортировки с учетом регистра, ToLower() НЕ является правильным способом выполнить сравнение без учета регистра.