LINQ如何查询值是否在范围列表之间?

假设我在数据库中有一个Person记录,并且该人有一个Age字段。

现在我有一个页面,允许我过滤特定年龄段的人。

例如,我可以选择多个范围选择,例如“0-10”,“11-20”,“31-40”。

所以在这种情况下,我会找回0到20之间的人员列表,以及30到40,但不是21-30。

我已经采用了年龄范围并填充了如下所示的范围列表:

class AgeRange { int Min { get; set; } int Max { get; set; } } List ageRanges = GetAgeRanges(); 

我使用LINQ to SQL进行数据库访问和查询,但我无法弄清楚如何查询范围。

我想做这样的事情,但当然,这不起作用,因为我无法根据SQL值查询我的本地值:

 var query = from person in db.People where ageRanges.Where(ages => person.Age >= ages.Min && person.Age <= ages.Max).Any()) select person; 

您可以使用PredicateBuilder动态构建PredicateBuilder

 static Expression> BuildAgePredicate(IEnumerable ranges) { var predicate = PredicateBuilder.False(); foreach (var r in ranges) { // To avoid capturing the loop variable var r2 = r; predicate = predicate.Or (p => p.Age >= r2.Min && p.Age <= r2.Max); } return predicate; } 

然后,您可以使用此方法,如下所示:

 var agePredicate = BuildAgePredicate(ageRanges); var query = db.People.Where(agePredicate); 

正如您提到的错误之一,您只能使用带有’Contains’方法的本地序列。 一种选择是创建所有允许年龄的列表,如下所示:

  var ages = ageRanges .Aggregate(new List() as IEnumerable, (acc, x) => acc.Union(Enumerable.Range(x.Min,x.Max - (x.Min - 1))) ); 

然后你可以打电话:

 People.Where(x => ages.Contains(x.Age)) 

对于这个故事要谨慎,如果你的范围很大,那么这将失败!

(这适用于小范围(您接受的最大年龄可能永远不会超过100),但是除此之外,上述两个命令都将变得非常昂贵!)

感谢Thomas的回答,我能够创建这个更通用的版本,似乎正在起作用:

  static IQueryable Between(this IQueryable query, Expression> predicate, IEnumerable ranges) { var exp = PredicateBuilder.False(); foreach (var range in ranges) { exp = exp.Or( Expression.Lambda>(Expression.GreaterThanOrEqual(predicate.Body, Expression.Constant(range.Min)), predicate.Parameters)) .And(Expression.Lambda>(Expression.LessThanOrEqual(predicate.Body, Expression.Constant(range.Max)), predicate.Parameters)); } return query.Where(exp); }