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