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

时间:2010-10-28 15:26:07

标签: c# linq linq-to-sql

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

现在我有了一个页面,可以让我过滤特定年龄段的人。

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

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

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

class AgeRange
{ 
     int Min { get; set; }
     int Max { get; set; }
}

List<AgeRange> 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;

4 个答案:

答案 0 :(得分:10)

您可以使用PredicateBuilder动态构建谓词:

static Expression<Func<Person, bool>> BuildAgePredicate(IEnumerable<AgeRange> ranges)
{
    var predicate = PredicateBuilder.False<Person>();
    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);

答案 1 :(得分:0)

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

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

然后你可以打电话:

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

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

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

答案 2 :(得分:0)

感谢Thomas的回答,我能够创建一个似乎正在运行的更通用的版本:

   static IQueryable<T> Between<T>(this IQueryable<T> query, Expression<Func<T, decimal>> predicate, IEnumerable<NumberRange> ranges)
    {
        var exp = PredicateBuilder.False<T>();

        foreach (var range in ranges)
        {
            exp = exp.Or(
                    Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(predicate.Body, Expression.Constant(range.Min)), predicate.Parameters))
                    .And(Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(predicate.Body, Expression.Constant(range.Max)), predicate.Parameters));
        }

        return query.Where(exp);
    }

答案 3 :(得分:0)

更简单的实现是使用Age.CompareTo() 我有一个类似的问题,并使用CompareTo解决了  在房屋数据库中,我想找到最大和最小范围内的房屋

from s in db.Homes.AsEnumerable() select s; houses = houses.Where( s=>s.Price.CompareTo(max) <= 0 && s.Price.CompareTo(min) >= 0 ) ;