一个实体框架表达式,用于查找与某些属性不匹配的实体

本文关键字:实体 查找 不匹配 属性 用于 一个 表达式 框架 | 更新日期: 2023-09-27 18:06:36

我需要一个在实体框架中工作的自定义表达式。这个方法应该有这样的签名:

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为空时,它返回所有实体。应该不返回任何实体

一个实体框架表达式,用于查找与某些属性不匹配的实体

这个怎么样?(只是想法,不是完整的代码)

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();
}

如果id列表为空,则返回一个空集合:

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支持的简单的"where+contains")。

但是,正式的方式可能是这样的,这对我来说似乎很有效(尽管这有点夸张):

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);
}