实体框架中的“不在”
本文关键字:不在 框架 实体 | 更新日期: 2023-09-27 18:21:47
我有以下实体
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();
您可以将子句 ALL 与 distinct(!=( 一起使用
var badBoys= from P in context.Persons
where badGuys.All(a => a.PersonId!= P.PersonId)
select P;
您可以实现自己的方法来制作必要的表达式树,如下所示:
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
可枚举对象的每个元素。
该方法的另一个优点是它的通用性,因为您可以为任何实体的任何属性调用它,例如 context.Persons.WhereNotIn(p => p.LastName, new[] { "Smith", "Brown", "Jones" })
.
LINQ to ENTITIES: NOT INCLUDE METHOD:
该方法应.Contains()
而不是 .包含。这需要一个基元类型枚举,因此只需枚举 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>
坏人,另一种选择是对收藏使用.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 EXCEPT(( 方法:
如果 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();
}