Выражение Entity Framework для поиска объектов, не соответствующих какому-либо свойству
Мне нужно пользовательское выражение, которое работает в Entity Framework. Метод должен иметь такую подпись:
var ids = new List<int> { 1, 2, 3 };
Context.FooEntities.WithoutId(e => e.Id, ids);
Это должно дать мне все Foo
лица, которые не имеют Id
свойства, которые соответствуют тем в списке.
Моя попытка основана на существующем примере здесь.
public static IQueryable<T> WithoutId<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.Not(
Expression.Call(
Expression.Constant(ids),
typeof(ICollection<int>).GetMethod("Contains"),
Expression.Property(parameter, property))),
parameter);
return entities.Where(expression);
}
Проблема в том, когда ids
пусто, то возвращает все сущности. Он не должен возвращать никаких сущностей.
4 ответа
Как насчет этого? (просто как идея, не законченный код)
IEnumerable<Entity> Get()
{
var ids = new[] { 1, 2, 3 };
if (ids.Length == 0) return Enumerable.Empty<Entity>();
return MyContext.MyEntities.Where(x=>ids.Contains(x.Id)).ToArray();
}
Если список идентификаторов пуст, просто верните пустую коллекцию:
if (ids.Count() != 0)
{
var property = (PropertyInfo)((MemberExpression)propertySelector.Body).Member;
ParameterExpression parameter = Expression.Parameter(typeof(T));
var expression = Expression.Lambda<Func<T, bool>>(
Expression.Not(
Expression.Call(
Expression.Constant(ids),
typeof(ICollection<int>).GetMethod("Contains"),
Expression.Property(parameter, property))),
parameter);
return entities.Where(expression);
}
return new List<T>().AsQueryable()//Or Enumerable.Empty<T>().AsQueryable();
Вы можете попробовать, как показано ниже.
public static IQueryable<T> WithoutId<T>(this IQueryable<T> entities,Expression<Func<T, int>> propertySelector,ICollection<int> ids) {
if (ids.Any())
{
var property = (PropertyInfo)((MemberExpression)propertySelector.Body).Member;
ParameterExpression parameter = Expression.Parameter(typeof(T));
var expression = Expression.Lambda<Func<T, bool>>(
Expression.Not(
Expression.Call(
Expression.Constant(ids),
typeof(ICollection<int>).GetMethod("Contains"),
Expression.Property(parameter, property))),parameter);
return entities.Where(expression);
}
else{
return Enumerable.Empty<T>().AsQueryable();
}
}
Мой вопрос может быть решен без сложного выражения, как указано в ответах выше (с использованием простого "где + содержит", который поддерживается EF).
Но формальный способ мог бы быть таким, который, кажется, работает для меня (даже если это излишне):
public static IQueryable<T> WithoutId<T>(
this IQueryable<T> entities,
Expression<Func<T, int>> propertySelector,
ICollection<int> ids) {
if (!ids.Any()) { // here is the trick
/*
expression = Expression.Lambda<Func<TEntity, bool>>(
Expression.Constant(false),
parameter);
*/
return Enumerable.Empty<T>().AsQueryable()
}
var property = (PropertyInfo)((MemberExpression)propertySelector.Body).Member;
ParameterExpression parameter = Expression.Parameter(typeof(T));
var expression = Expression.Lambda<Func<T, bool>>(
Expression.Not(
Expression.Call(
Expression.Constant(ids),
typeof(ICollection<int>).GetMethod("Contains"),
Expression.Property(parameter, property))),
parameter);
return entities.Where(expression);
}