Короче говоря, я хочу сделать , что этот парень сделал , но с Entity Framework 6.
Реализация предложенного решения приводит к ошибке "Выражение LINQТип узла 'Invoke' не поддерживается в LINQ to Entities. " Поскольку в предлагаемом решении используется Invoke
, это, очевидно, проблема.
Я понимаю, что есть способ использовать aпользовательский метод Compose для переписывания дерева выражений без использования Invoke
, но я не могу обернуться вокруг него.
Вот что я пытаюсь написать.
Я строю IQueryable<TEntity>
динамически, используя QueryParameters
объект, который является просто набором свойств, которые можно использовать для предложений WHERE.TEntity
- это стандартная EF-сущность с первым кодом, с аннотациями данных повсюду.Конструкция запроса выглядит примерно так:
IQueryable<TEntity> query = Context.Set<TEntity>();
if (queryParams == null)
return query;
if (!string.IsNullOrWhiteSpace(queryParams.FirstName))
{
if (queryParams.ExactSearch)
{
query = query.Where(x => x.FirstName == queryParams.FirstName);
}
else
{
if (queryParams.PreferStartsWith)
{
query = query.Where(
x => x.FirstName.ToLower()
.StartsWith(
queryParams.FirstName
.ToLower()));
}
else
{
query = query.Where(
x => x.FirstName.ToLower()
.Contains(
queryParams.FirstName
.ToLower()));
}
}
}
// ... repeat for all of queryParams' string props.
// DateTime, int, bool, etc have their own filters.
Это повторяется для каждого параметра запроса для строкового поля, которое будет запрошено.Очевидно, это приводит к многократному повторению кода.Я хотел бы иметь возможность написать фильтр с такой подписью:
public static IQueryable<TEntity> Search<TEntity>(
this IQueryable<TEntity> query,
Expression<Func<TEntity, string>> fieldExpression,
string searchValue,
bool exactSearch = true,
bool useStartsWithOverContains = false) {...}
, который я затем смогу потреблять так:
if (!string.IsNullOrWhiteSpace(queryParams.FirstName))
{
query = query.Search(
x => x.FirstName,
queryParams.FirstName,
queryParams.ExactSearch,
queryParams.PreferStartsWith);
}
Ближайшее определение, которое я получилэтот метод расширения приведен ниже, но, как уже упоминалось, он выдает, что «Invoke» не поддерживается в LINQ to Entities »:
public static IQueryable<TEntity> Search<TEntity>(
this IQueryable<TEntity> query,
Expression<Func<TEntity, string>> fieldExpression,
string searchValue,
bool exactSearch = true,
bool useStartsWithOverContains = false)
{
if (string.IsNullOrWhiteSpace(searchValue))
return query;
searchValue = searchValue.Trim();
Expression<Func<TEntity, bool>> expression;
if (exactSearch)
{
var x = Expression.Parameter(typeof(TEntity), "x");
var left = Expression.Invoke(fieldExpression, x);
var right = Expression.Constant(searchValue);
var equalityExpression = Expression.Equal(left, right);
expression = Expression.Lambda<Func<TEntity, bool>>(
equalityExpression,
x);
}
else
{
searchValue = searchValue.ToLower();
var x = Expression.Parameter(typeof(TEntity), "x");
var fieldToLower = Expression.Call(
Expression.Invoke(fieldExpression, x),
typeof(string).GetMethod(
"ToLower",
Type.EmptyTypes));
var searchValueExpression =
Expression.Constant(searchValue);
var body = Expression.Call(
fieldToLower,
typeof(string).GetMethod(
useStartsWithOverContains ? "StartsWith" : "Contains",
new[] { typeof(string) }),
searchValueExpression);
expression = Expression.Lambda<Func<TEntity, bool>>(
body,
x);
}
return query.Where(expression);
}
Я начал включать метод Compose Я упомянул, но я очень быстро заблудился, и поэтому удалил его.
Открыт для любых указаний!Спасибо!