Created
April 16, 2020 19:53
-
-
Save enisn/3a617f11dd2b375fe7fb6927fe360337 to your computer and use it in GitHub Desktop.
Challenge #1 - Solution 2 - FilterBase.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class FilterBase : IFilter | |
| { | |
| public virtual CombineType CombineWith { get; set; } | |
| public virtual IQueryable<TEntity> ApplyFilterTo<TEntity>(IQueryable<TEntity> query) | |
| { | |
| var parameter = Expression.Parameter(typeof(TEntity), "x"); | |
| var exp = BuildExpression(typeof(TEntity), parameter); | |
| if (exp == null) | |
| return query; | |
| var lambda = Expression.Lambda<Func<TEntity, bool>>(exp, parameter); | |
| return query.Where(lambda); | |
| } | |
| public virtual Expression BuildExpression(Type entityType, Expression body) | |
| { | |
| Expression finalExpression = null; | |
| var _type = this.GetType(); | |
| foreach (var entityProperty in entityType.GetProperties()) | |
| { | |
| try | |
| { | |
| var filterProperty = _type.GetProperty(entityProperty.Name); | |
| if (filterProperty == null) | |
| continue; | |
| var val = filterProperty.GetValue(this); | |
| if (val == null) | |
| continue; | |
| var attribute = filterProperty.GetCustomAttribute<FilteringOptionsBaseAttribute>(false); | |
| if (attribute != null) | |
| { | |
| var expression = attribute.BuildExpression(body, entityProperty, val); | |
| finalExpression = Combine(finalExpression, expression); | |
| continue; | |
| } | |
| if (val is IFilter filter) | |
| { | |
| if (typeof(ICollection).IsAssignableFrom(entityProperty.PropertyType) || (entityProperty.PropertyType.IsConstructedGenericType && typeof(IEnumerable).IsAssignableFrom(entityProperty.PropertyType))) | |
| { | |
| var type = entityProperty.PropertyType.GetGenericArguments().FirstOrDefault(); | |
| var prop = Expression.Property(body, entityProperty.Name); | |
| var parameter = Expression.Parameter(type, "a"); | |
| var methodInfo = typeof(Enumerable).GetMethods().LastOrDefault(x => x.Name == "Any"); | |
| var method = methodInfo.MakeGenericMethod(type); | |
| var query = filter.BuildExpression(type, body: parameter); | |
| var lambda = Expression.Lambda(query, parameter); | |
| var expression = Expression.Call( | |
| method: method, | |
| instance: null, | |
| arguments: new Expression[] { prop, lambda } | |
| ); | |
| finalExpression = Combine(finalExpression, expression); | |
| continue; | |
| } | |
| else | |
| { | |
| var parameter = Expression.Property(body, entityProperty.Name); | |
| var expression = filter.BuildExpression(entityProperty.PropertyType, parameter); | |
| finalExpression = Combine(finalExpression, expression); | |
| continue; | |
| } | |
| } | |
| if (val is IFilterableType filterableProperty) | |
| { | |
| var expression = filterableProperty.BuildExpression(body, entityProperty, val); | |
| finalExpression = Combine(finalExpression, expression); | |
| } | |
| else | |
| { | |
| var comparison = Expression.Equal( | |
| Expression.Property(body, entityProperty.Name), | |
| Expression.Constant(val) | |
| ); | |
| finalExpression = Combine(finalExpression, comparison); | |
| } | |
| } | |
| catch (Exception ex) | |
| { | |
| Debug.WriteLine(ex?.ToString()); | |
| } | |
| } | |
| return finalExpression; | |
| } | |
| private protected virtual Expression Combine(Expression body, Expression extend) | |
| { | |
| if (body == null) | |
| return extend; | |
| if (extend == null) | |
| return body; | |
| switch (CombineWith) | |
| { | |
| case CombineType.And: | |
| return Expression.And(body, extend); | |
| case CombineType.Or: | |
| return Expression.Or(body, extend); | |
| default: | |
| return extend; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment