如何在 Entity Framework 中查找具有指定日期范围列表的日期?
How to find a date with a list of specified date ranges in Entity Framework?
我创建了一个 class 的 IEnumerable 来包含日期范围。 class 看起来像这样:
public class Range<T>
where T: struct
{
public T Start { get; set; }
public T End { get; set; }
}
我想查找我的集合中日期列在任何指定日期范围内的所有记录。这是我的尝试:
deals = deals.Where(
deal =>
criteria.DateRanges.Any(
dt =>
deal.CloseDate >= dt.Start &&
deal.CloseDate < dt.End.Value.AddDays(1)));
我认为这会引发错误,因为 EF 不知道如何将 criteria.DateRanges.Any()
转换为 SQL。那么,您将如何编写此代码来查找与任何日期范围匹配的日期?
您可以为此使用 LinqKit:
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);
另一种选择是使用 Expression Trees,但这对于您正在尝试做的事情来说似乎有点过分了。
同意@stuartd,如果有一些范围条件,您可以构建自己的表达式,为每个范围创建一个 And
表达式,并在末尾将它们组合成几个 Ors
。您可以像这样创建一个静态泛型方法:
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);
}
稍后在您的代码中,您可以执行如下操作:
var rangeExp=RangeExpression<Deal>("CloseDate",criteria.DateRanges);
deals = deals.Where(rangeExp);
我创建了一个 class 的 IEnumerable 来包含日期范围。 class 看起来像这样:
public class Range<T>
where T: struct
{
public T Start { get; set; }
public T End { get; set; }
}
我想查找我的集合中日期列在任何指定日期范围内的所有记录。这是我的尝试:
deals = deals.Where(
deal =>
criteria.DateRanges.Any(
dt =>
deal.CloseDate >= dt.Start &&
deal.CloseDate < dt.End.Value.AddDays(1)));
我认为这会引发错误,因为 EF 不知道如何将 criteria.DateRanges.Any()
转换为 SQL。那么,您将如何编写此代码来查找与任何日期范围匹配的日期?
您可以为此使用 LinqKit:
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);
另一种选择是使用 Expression Trees,但这对于您正在尝试做的事情来说似乎有点过分了。
同意@stuartd,如果有一些范围条件,您可以构建自己的表达式,为每个范围创建一个 And
表达式,并在末尾将它们组合成几个 Ors
。您可以像这样创建一个静态泛型方法:
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);
}
稍后在您的代码中,您可以执行如下操作:
var rangeExp=RangeExpression<Deal>("CloseDate",criteria.DateRanges);
deals = deals.Where(rangeExp);