using System.Linq.Expressions;
using Domain.Forecasts;
namespace EfAdapter.Extensions
{
public static class QueryExtensions
{
public static IQueryable<T> Between<T, TKey>(
this IQueryable<T> query,
Expression<Func<T, TKey>> keySelector,
TKey minValue,
TKey maxValue)
where TKey : IComparable<TKey>
{
var parameter = keySelector.Parameters.Single();
var body = Expression.AndAlso(
Expression.GreaterThanOrEqual(keySelector.Body, Expression.Constant(minValue)),
Expression.LessThanOrEqual(keySelector.Body, Expression.Constant(maxValue))
);
var predicate = Expression.Lambda<Func<T, bool>>(body, parameter);
return query.Where(predicate);
}
public static IQueryable<T> BetweenYearWeek<T>(
this IQueryable<T> query,
Expression<Func<T, int>> yearWeekSelector,
YearWeek minValue,
YearWeek maxValue)
{
var parameter = yearWeekSelector.Parameters.Single();
var body = Expression.AndAlso(
Expression.GreaterThanOrEqual(yearWeekSelector.Body, Expression.Constant(minValue.AsInt())),
Expression.LessThanOrEqual(yearWeekSelector.Body, Expression.Constant(maxValue.AsInt()))
);
var predicate = Expression.Lambda<Func<T, bool>>(body, parameter);
return query.Where(predicate);
}
}
/// <summary>
/// Use as:
/// .InDateTimeRange(x => x.ValidFrom, x => x.ValidTo, periodFrom, periodTo)
///
/// Is about equal to:
/// .Where(x => x.ValidFrom == null || x.ValidFrom <= periodFrom)
/// .Where(x => x.ValidTo == null || x.ValidTo >= periodTo)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="query"></param>
/// <param name="minSelector"></param>
/// <param name="maxSelector"></param>
/// <param name="minValue"></param>
/// <param name="maxValue"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static IQueryable<T> InDateTimeRange<T>(
this IQueryable<T> query,
Expression<Func<T, DateTime?>> minSelector,
Expression<Func<T, DateTime?>> maxSelector,
DateTime? minValue,
DateTime? maxValue)
{
if (query == null) throw new ArgumentNullException(nameof(query));
if (minSelector == null) throw new ArgumentNullException(nameof(minSelector));
if (maxSelector == null) throw new ArgumentNullException(nameof(maxSelector));
// Deze waarden hebben we al vooraf
minValue ??= DateTime.MinValue;
maxValue ??= DateTime.MaxValue;
var minPropertyName = GetPropertyName(minSelector);
var maxPropertyName = GetPropertyName(maxSelector);
var parameter = Expression.Parameter(typeof(T), "x");
var validFromExpression = Expression.Property(parameter, minPropertyName);
var validToExpression = Expression.Property(parameter, maxPropertyName);
var nullCheckValidFrom = Expression.Equal(validFromExpression, Expression.Constant(null));
var validFromCondition = Expression.LessThanOrEqual(validFromExpression, Expression.Constant(minValue, typeof(DateTime?)));
var nullCheckValidTo = Expression.Equal(validToExpression, Expression.Constant(null));
var validToCondition = Expression.GreaterThanOrEqual(validToExpression, Expression.Constant(maxValue, typeof(DateTime?)));
var body = Expression.AndAlso(
Expression.OrElse(nullCheckValidFrom, validFromCondition),
Expression.OrElse(nullCheckValidTo, validToCondition)
);
return query.Where(Expression.Lambda<Func<T, bool>>(body, parameter));
}
private static string GetPropertyName<T, TProp>(Expression<Func<T, TProp>> propertyExpression)
{
if (propertyExpression.Body is MemberExpression memberExpression)
return memberExpression.Member.Name;
throw new ArgumentException("Invalid property expression", nameof(propertyExpression));
}
public static IQueryable<T> InDateTimeRangeIf<T>(this IQueryable<T> source,
bool condition,
Expression<Func<T, DateTime?>> minSelector,
Expression<Func<T, DateTime?>> maxSelector,
DateTime? minValue,
DateTime? maxValue)
{
return condition? source.InDateTimeRange(minSelector, maxSelector, minValue, maxValue) : source;
}
}
812000cookie-checkLinq QueryExtensions as expressions for SQL