Skip to content

Instantly share code, notes, and snippets.

@princefishthrower
Created March 26, 2021 07:30
Show Gist options
  • Save princefishthrower/6620fcded6b2600bbd10f4100c55401c to your computer and use it in GitHub Desktop.
Save princefishthrower/6620fcded6b2600bbd10f4100c55401c to your computer and use it in GitHub Desktop.
Dynamic Where Expressions With EF Core
public List<AppParkingOrderModel> GetHourlyIntersectedBookingsByFacility(string facilityName)
{
var searchCriteria = new List<Expression<Func<AppParkingOrderModel, bool>>>();
var now = DateTime.Now;
var yearFromNow = now.AddYears(1).Year;
var startDateTime = new DateTime(now.Year, 1, 1, 0, 0, 0);
var endDateTime = new DateTime(yearFromNow, 1, 1, 0, 0, 0);
var hours = (endDateTime - startDateTime).TotalHours;
// for each hour this year, calculate and store the parking calculation model for this location
for (var i = 0; i < hours; i++)
{
var dateTime = startDateTime.AddHours(i);
searchCriteria.Add(x => dateTime > x.StartDate && dateTime < x.EndDate);
}
// don't forget the facility criteria
searchCriteria.Add(x => x.FacilityName == facilityName);
// We're done building our search criteria - here is where we use the fancy join
var joinedSearchCriteria = ExpressionReplacer.Join(Expression.And, searchCriteria);
using (var dbContext = this.dbContextFactory.GetContext())
{
var query = dbContext.AppParkingOrders.AsQueryable();
query = query.Where(joinedSearchCriteria);
return query.ToList();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace YOUR_NAMESPACE_HERE
{
public class ExpressionReplacer : ExpressionVisitor
{
private readonly Func<Expression, Expression> replacer;
public ExpressionReplacer(Func<Expression, Expression> replacer)
{
this.replacer = replacer;
}
public override Expression Visit(Expression node)
{
return base.Visit(replacer(node));
}
public static T ReplaceParameter<T>(T expr, ParameterExpression toReplace, ParameterExpression replacement)
where T : Expression
{
var replacer = new ExpressionReplacer(e => e == toReplace ? replacement : e);
return (T)replacer.Visit(expr);
}
public static Expression<Func<T, TReturn>> Join<T, TReturn>(Func<Expression, Expression, BinaryExpression> joiner, IReadOnlyCollection<Expression<Func<T, TReturn>>> expressions)
{
if (!expressions.Any())
{
throw new ArgumentException("No expressions were provided");
}
var firstExpression = expressions.First();
var otherExpressions = expressions.Skip(1);
var firstParameter = firstExpression.Parameters.Single();
var otherExpressionsWithParameterReplaced = otherExpressions.Select(e => ReplaceParameter(e.Body, e.Parameters.Single(), firstParameter));
var bodies = new[] { firstExpression.Body }.Concat(otherExpressionsWithParameterReplaced);
var joinedBodies = bodies.Aggregate(joiner);
return Expression.Lambda<Func<T, TReturn>>(joinedBodies, firstParameter);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment