C# &引用;不在「;实体框架内

C# &引用;不在「;实体框架内,c#,entity-framework,linq,C#,Entity Framework,Linq,我有以下实体 public class Person { public int PersonId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } } 并且有一个名单列出坏人 我要做的是从所有人中选择,除了坏人列表中的人 我的代码 context.Persons .where(p => !badGuys.Contain(p))

我有以下实体

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
并且有一个名单
列出坏人

我要做的是从所有人中选择,除了
坏人
列表中的人

我的代码

context.Persons
    .where(p => !badGuys.Contain(p))
    .ToList()
但我犯了个错误

此类型中仅支持基元类型或枚举类型 上下文


如何修复此问题?

您可以创建一个包含坏人ID的数组,并过滤掉这些ID(它们属于基本类型,因此应该可以正常工作):


您可以实现自己的方法来创建必要的表达式树,如下所示:

    public static IQueryable<TEntity> WhereNotIn<TEntity, TValue>(
        this IQueryable<TEntity> queryable,
        Expression<Func<TEntity, TValue>> valueSelector,
        IEnumerable<TValue> values)
        where TEntity : class
    {
        if (queryable == null)
            throw new ArgumentNullException("queryable");

        if (valueSelector == null)
            throw new ArgumentNullException("valueSelector");

        if (values == null)
            throw new ArgumentNullException("values");

        if (!values.Any())
            return queryable.Where(e => true);

        var parameterExpression = valueSelector.Parameters.Single();

        var equals = from value in values
                     select Expression.NotEqual(valueSelector.Body, Expression.Constant(value, typeof (TValue)));

        var body = equals.Aggregate(Expression.And);

        return queryable.Where(Expression.Lambda<Func<TEntity, bool>>(body, parameterExpression));
    }
}
此方法与以下方法相同:

context.Persons.Where(p => p.PersonId != badGuys[0]
                        && p.PersonId != badGuys[1]
                        . . .
                        && p.PersonId != badGuys[N]);
对于
坏人
可枚举对象的每个元素


该方法的另一个优点是它的通用性,因为您可以为任何实体的任何属性调用它,例如
context.Persons.WhereNotIn(p=>p.LastName,new[]{“Smith”、“Brown”、“Jones”})
LINQ to ENTITIES:notcontains method:

方法应该是
.Contains()
而不是.Contain。这需要一个基元类型枚举,所以只需枚举badGuys集合的键字段,并在查询上下文时在
Where
子句中调用
.Contains()

//get the list of bad guys
List<Person> badGuys = ...
//get simple primitive type enumeration
var badGuysIDs = badGuys.Select(t => t.PersonId).ToList();

using(Context c = new Context())
{
   var badPersons = c.Persons.Where(t => !badGuysIDs.Contains(t.PersonId)).ToList();
}
LINQ to ENTITIES EXCEPT()方法:

如果Persons表中有大量行,则上述方法将不理想,因为它将枚举整个集合。如果有大量行,则需要在枚举之前在数据库端执行排除。要做到这一点,只需告诉数据库如何比较两个对象的相等性,如中所示

公共类人员比较者:IEqualityComparer
{
公共bool Equals(personx,persony){return x.Id==y.Id;}
public int GetHashCode(Person){return Person.PersonId.GetHashCode();}
}
使用(Context c=new Context())
{
//得到坏人的名单
列出坏人=。。。
var goodPersons=c.Persons.Except(坏人,PersonComparer()).ToList();
}

您可以将子句ALL与distinct(!=)一起使用


这是一个不错的解决方案,但就性能而言不是一个好的解决方案。我宁愿使用ANY语句来提高性能。另外,EF本身就支持它,所以为什么不采用这种方法呢?@hbulens我不确定EF是否能够处理
任何
,如果它不能处理
包含的
。但这是可能的。至于性能,我认为这两个查询在DB级别的执行计划相似。@MarkShevchenko这是一个非常好的方法,但因此我必须使用
p.PersonId
进行过滤,您的解决方案和@W0lf解决方案有什么区别?@MohamedBadr,如我所见,使用您的方法生成的SQL类似于
WHERE(2[Extent1].[PersonId])和(1[Extent1].[PersonId])
,而从@W0lf answer生成的代码类似于
WHERE NOT([Extent1].[PersonId])(2,1))
哪个查询效率更高?您可以通过删除
.ToArray()来提高效率类似这样:
var badGuyIds=badGuys.Select(x=>x.PersonId)
从而防止对
badGuyId
进行不必要的查询,因为对
Persons
的第二次查询无论如何都会这样做。。。
context.Persons.Where(p => p.PersonId != badGuys[0]
                        && p.PersonId != badGuys[1]
                        . . .
                        && p.PersonId != badGuys[N]);
//get the list of bad guys
List<Person> badGuys = ...
//get simple primitive type enumeration
var badGuysIDs = badGuys.Select(t => t.PersonId).ToList();

using(Context c = new Context())
{
   var badPersons = c.Persons.Where(t => !badGuysIDs.Contains(t.PersonId)).ToList();
}
//get the list of bad guys
List<Person> badGuys = ...

using(Context c = new Context())
{
   //enumerate Persons, then exclude badPersons
   var goodPersons = c.Persons.ToList().Except(badPersons);
}
public class PersonComparer: IEqualityComparer<Persons> 
{
     public bool Equals(Person x, Person y) {return x.Id == y.Id;}
     public int GetHashCode(Person person) {return person.PersonId.GetHashCode();}
}


using(Context c = new Context())
{
    //get the list of bad guys
    List<Person> badGuys = ...

   var goodPersons = c.Persons.Except(badPersons, PersonComparer()).ToList();
}
var badBoys= from P in context.Persons
         where badGuys.All(a => a.PersonId!= P.PersonId)
         select P;