How to find a date with a list of specified date ranges in Entity Framework?

寵の児 提交于 2019-12-12 07:24:55

问题


I have an IEnumerable of a class that I created to contain date ranges. That class looks like this:

public class Range<T>
    where T: struct 
{
    public T Start { get; set; }
    public T End { get; set; }
}

I want to find all the records in my set where a date column falls within ANY of the specified date ranges. This was my attempt:

deals = deals.Where(
            deal =>
                criteria.DateRanges.Any(
                  dt =>
                    deal.CloseDate >= dt.Start &&
                    deal.CloseDate < dt.End.Value.AddDays(1)));

This throws an error I assume because EF doesn't know how to translate criteria.DateRanges.Any() to SQL. So how would you write this to find dates that match ANY of the date ranges?


回答1:


You can use LinqKit for this:

var expr = PredicateBuilder.False<Deal>();
foreach(var range in criteria.DateRanges)
   expr = expr.Or(d => dt.CloseDate >= range.Start && dt.CloseDate < range.End);
deals = deals.AsExpandable().Where(expr);

Another option would be to use Expression Trees but that seems a bit overkill for what you're trying to do.




回答2:


Agreed with @stuartd, if there are a few range conditions you can build your own expression creating one And expression per range, and combining them at the end in several Ors. You could create a static generic method like this:

public static Expression<Func<T,bool>> RangeExpression<T>(string property, IEnumerable<Range<DateTime>> criterias )
{
            Expression result = null;
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "o");
            foreach (var item in criterias)
            {
                var value1 = item.Start.Date;
                var value2 = item.End.Date.AddDays(1);

                MemberExpression memberExpression1 = Expression.PropertyOrField(parameterExpression, property);
                MemberExpression memberExpression2 = Expression.PropertyOrField(parameterExpression, property);

                ConstantExpression valueExpression1 = Expression.Constant(value1, typeof(DateTime));
                ConstantExpression valueExpression2 = Expression.Constant(value2, typeof(DateTime));

                BinaryExpression binaryExpression1 = Expression.GreaterThanOrEqual(memberExpression1, valueExpression1);
                BinaryExpression binaryExpression2 = Expression.LessThan(memberExpression2, valueExpression2);

                var ret1 = Expression.Lambda<Func<T, bool>>(binaryExpression1, parameterExpression);
                var ret2 = Expression.Lambda<Func<T, bool>>(binaryExpression2, parameterExpression);

                Expression and = Expression.And(ret1, ret2);

                result = result!=null?Expression.OrElse(result, and):and;   
            }
            return Expression.Lambda < Func<T,bool>>(result, parameterExpression);
}

And later in your code, you could do something like this:

var rangeExp=RangeExpression<Deal>("CloseDate",criteria.DateRanges);
deals = deals.Where(rangeExp);


来源:https://stackoverflow.com/questions/36703908/how-to-find-a-date-with-a-list-of-specified-date-ranges-in-entity-framework

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!