繁体   English   中英

实体框架中的“不在”

[英]“Not In” in Entity Framework

我有以下实体

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

并列出List<Person> badGuys

我想要做的是从除badGuys列表中的人之外的所有人中选择

我的守则

context.Persons
    .where(p => !badGuys.Contain(p))
    .ToList()

但是我收到了一个错误

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

如何解决这个问题?

你可以创建一个包含坏人的ID的数组并过滤掉那些id(它们是原始类型,所以它应该工作):

var badGuyIds = badGuys.Select(x => x.PersonId).ToArray();

context.Persons
    .Where(p => !badGuyIds.Contain(p.PersonId))
    .ToList();

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

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

现在你可以调用这个扩展方法

var badGuys = new int[] { 100, 200, 300 };
context.Persons.WhereNotIn(p => p.PersionId, badGuys);

这个方法与以下内容相同:

context.Persons.Where(p => p.PersonId != badGuys[0]
                        && p.PersonId != badGuys[1]
                        . . .
                        && p.PersonId != badGuys[N]);

对于badGuys可枚举对象的每个元素。

该方法的另一个优点是它的普遍性,因为你可以为任何实体的任何属性调用它,fe context.Persons.WhereNotIn(p => p.LastName, new[] { "Smith", "Brown", "Jones" })

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

var badBoys= from P in context.Persons
         where badGuys.All(a => a.PersonId!= P.PersonId)
         select P;

LINQ to ENTITIES:NOT CONTAINS 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 OBJECTS EXCEPT()方法:

另一个选择,如果你已经有你的List<Person> of badguys,那就是在你的集合中使用.Except .Except()方法。 在将集合枚举到对象之后,必须执行此操作。

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

LINQ to ENTITIES除外()方法:

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM