Как использовать Func в выражении с Linq to Entity Framework?
Я пытаюсь написать метод расширения linq to entity, который берет Func, чтобы выбрать свойство Id и сравнить его со списком идентификаторов.
Классы
public class A
{
public int AId { get; set; }
}
public class B
{
public int BId { get; set; }
}
Метод расширения
public static IQueryable<T> WithId<T>(this IQueryable<T> entities,
Func<T, int> selector, IList<int> ids)
{
Expression<Func<T, bool>> expression = x => ids.Contains(selector(x));
return entities.Where(expression); // error here (when evaluated)
}
Метод вызова
var ids = new List<int> { 1, 2, 3 };
DbContext.EntityAs.WithId(e => e.AId, ids);
DbContext.EntityBs.WithId(e => e.BId, ids);
Проблема, с которой я сталкиваюсь, заключается в том, что она пытается вызвать функцию, которая не разрешена в Entity Framework.
Как я могу использовать селектор свойств (Func) для оценки запроса?
1 ответ
Решение
Вам придется пройти Expression<Func<T, int>>
вместо Func<T, int>
и создайте полное выражение самостоятельно. Это сделает свое дело:
public static IQueryable<T> WithId<T>(this IQueryable<T> entities,
Expression<Func<T, int>> propertySelector, ICollection<int> ids)
{
var property =
(PropertyInfo)((MemberExpression)propertySelector.Body).Member;
ParameterExpression parameter = Expression.Parameter(typeof(T));
var expression = Expression.Lambda<Func<T, bool>>(
Expression.Call(
Expression.Constant(ids),
typeof(ICollection<int>).GetMethod("Contains"),
Expression.Property(parameter, property)),
parameter);
return entities.Where(expression);
}
Когда вы пытаетесь сохранить ваш код СУХИМЫМ при работе с O/RM, вам часто приходится возиться с деревьями выражений. Вот еще один забавный пример.