Написание обобщённой LINQ-фильтрации
Я хочу написать абстрактную фильтрацию по полям моделей.
public static class Filter
{
public static List<IModelContext> FilterWith<IModelContext>(this DbSet<IModelContext> dbSet, string property, object compared) where IModelContext : class
{
return dbSet.Where(x => x.IsFilter(property, compared)).ToList();
}
public static bool IsFilter<IModelContext>(this IModelContext model, string property, object compared)
{
return model?.GetType().GetProperty(property)?.GetValue(model, null)?.Equals(compared) ?? false;
}
}
В тестовом консольном приложении я вызываю этот метод
bool filtered = ctx.Measure.First().IsFilter("Conditions", "value");
List<Measure> filteredList = ctx.Measure.FilterWith("Conditions", "value");
Метод IsFilter по одиночке работает, но вкупе с LINQ запросом отваливается с ошибкой. При вызове FilterWith выбрасывает в ошибку:
System.InvalidOperationException: "The LINQ expression 'DbSet<Measure>()
.Where(m => m
.IsFilter(
property: __property_0,
compared: __compared_1))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information."
Как только их не компоновал, миксовал сравнения в предикате:
- tostring equals
.GetValue(model, null).ToString().Equals(compared.ToString(), StringComparison.CurrentCultureIgnoreCase) ?? false;)
- ==
.GetValue(model, null) == compared
По всей видимости суть в неявных операциях во время одиночного сравнения которые LINQ не может принять, но не могу понять в чем именно.
Ответы (1 шт):
Явное вычисление на стороне клиента
В некоторых случаях, например, в указанных ниже, может потребоваться явное принудительное вычисление на стороне клиента.
Объем данных мал, поэтому вычисление в клиенте не приводит к значительному снижению производительности. Используемый оператор LINQ не преобразуется на стороне сервера.
гласит документация. Стоило лишь открыть ссылку из ошибки. solution:
return dbSet
.AsEnumerable() // <-- added
.Where(x => x.IsFilter(property, compared));