using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace EFDemo
{
/// <summary>
/// Defines the <see cref="QueryExtention" />.
/// </summary>
public static class QueryExtention
{
/// <summary>
/// The Where.
/// </summary>
/// <typeparam name="T">.</typeparam>
/// <param name="source">The source<see cref="IQueryable{T}"/>.</param>
/// <param name="whereConditions">The whereConditions<see cref="List{WhereCondition}"/>.</param>
/// <returns>The <see cref="IQueryable{T}"/>.</returns>
public static IQueryable<T> Where<T>(this IQueryable<T> source, List<WhereCondition> whereConditions) where T : class
{
foreach (var query in whereConditions)
{
source = source.Where(query.Filters.AsExpression<T>(query.Link));
}
return source;
}
}
/// <summary>
/// Defines the Operators.
/// </summary>
public enum Operators
{
/// <summary>
/// Defines the None.
/// </summary>
None = 0,
/// <summary>
/// Defines the Equal.
/// </summary>
Equal = 1,
/// <summary>
/// Defines the Contains.
/// </summary>
Contains = 2,
/// <summary>
/// Defines the StartWith.
/// </summary>
StartWith = 3,
/// <summary>
/// Defines the EndWidth.
/// </summary>
EndWidth = 4,
/// <summary>
/// Defines the Range.
/// </summary>
Range = 5,
/// <summary>
/// Defines the GreaterThan.
/// </summary>
GreaterThan = 6,
/// <summary>
/// Defines the GreaterThanOrEqual.
/// </summary>
GreaterThanOrEqual = 7,
/// <summary>
/// Defines the LessThan.
/// </summary>
LessThan = 8,
/// <summary>
/// Defines the LessThanOrEqual.
/// </summary>
LessThanOrEqual = 9,
}
/// <summary>
/// Defines the ConditionLink.
/// </summary>
public enum ConditionLink
{
/// <summary>
/// Defines the OrElse.
/// </summary>
OrElse = 1,
/// <summary>
/// Defines the AndAlso.
/// </summary>
AndAlso = 2
}
/// <summary>
/// Defines the <see cref="Query" />.
/// </summary>
public class Query
{
/// <summary>
/// Gets or sets the Name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the Operator.
/// </summary>
public Operators Operator { get; set; }
/// <summary>
/// Gets or sets the Value.
/// </summary>
public object Value { get; set; }
/// <summary>
/// Gets or sets the ValueMin.
/// </summary>
public object ValueMin { get; set; }
/// <summary>
/// Gets or sets the ValueMax.
/// </summary>
public object ValueMax { get; set; }
}
/// <summary>
/// Defines the <see cref="QueryCollection" />.
/// </summary>
public class QueryCollection : Collection<Query>
{
/// <summary>
/// The AsExpression.
/// </summary>
/// <typeparam name="T">.</typeparam>
/// <param name="condition">The condition<see cref="ConditionLink?"/>.</param>
/// <returns>The <see cref="Expression{Func{T, bool}}"/>.</returns>
public Expression<Func<T, bool>> AsExpression<T>(ConditionLink? condition = ConditionLink.OrElse) where T : class
{
Type targetType = typeof(T);
TypeInfo typeInfo = targetType.GetTypeInfo();
var parameter = Expression.Parameter(targetType, "m");
Expression expression = null;
Func<Expression, Expression, Expression> Append = (exp1, exp2) =>
{
if (exp1 == null)
{
return exp2;
}
return (condition ?? ConditionLink.OrElse) == ConditionLink.OrElse ? Expression.OrElse(exp1, exp2) : Expression.AndAlso(exp1, exp2);
};
foreach (var item in this)
{
var property = typeInfo.GetProperty(item.Name);
if (property == null ||
!property.CanRead ||
(item.Operator != Operators.Range && item.Value == null) ||
(item.Operator == Operators.Range && item.ValueMin == null && item.ValueMax == null))
{
continue;
}
Type realType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
if (item.Value != null)
{
item.Value = Convert.ChangeType(item.Value, realType);
}
Expression<Func<object>> valueLamba = () => item.Value;
switch (item.Operator)
{
case Operators.Equal:
{
expression = Append(expression, Expression.Equal(Expression.Property(parameter, item.Name),
Expression.Convert(valueLamba.Body, property.PropertyType)));
break;
}
case Operators.GreaterThan:
{
expression = Append(expression, Expression.GreaterThan(Expression.Property(parameter, item.Name),
Expression.Convert(valueLamba.Body, property.PropertyType)));
break;
}
case Operators.GreaterThanOrEqual:
{
expression = Append(expression, Expression.GreaterThanOrEqual(Expression.Property(parameter, item.Name),
Expression.Convert(valueLamba.Body, property.PropertyType)));
break;
}
case Operators.LessThan:
{
expression = Append(expression, Expression.LessThan(Expression.Property(parameter, item.Name),
Expression.Convert(valueLamba.Body, property.PropertyType)));
break;
}
case Operators.LessThanOrEqual:
{
expression = Append(expression, Expression.LessThanOrEqual(Expression.Property(parameter, item.Name),
Expression.Convert(valueLamba.Body, property.PropertyType)));
break;
}
case Operators.Contains:
{
//var nullCheck = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, Expression.Property(parameter, item.Name)));
var contains = Expression.Call(Expression.Property(parameter, item.Name), "Contains", null,
Expression.Convert(valueLamba.Body, property.PropertyType));
//expression = Append(expression, Expression.AndAlso(nullCheck, contains));
expression = Append(expression, contains);
break;
}
case Operators.StartWith:
{
//var nullCheck = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, Expression.Property(parameter, item.Name)));
var startsWith = Expression.Call(Expression.Property(parameter, item.Name), "StartsWith", null,
Expression.Convert(valueLamba.Body, property.PropertyType));
expression = Append(expression, startsWith);
break;
}
case Operators.EndWidth:
{
//var nullCheck = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, Expression.Property(parameter, item.Name)));
var endsWith = Expression.Call(Expression.Property(parameter, item.Name), "EndsWith", null,
Expression.Convert(valueLamba.Body, property.PropertyType));
expression = Append(expression, endsWith);
break;
}
case Operators.Range:
{
Expression minExp = null, maxExp = null;
if (item.ValueMin != null)
{
var minValue = Convert.ChangeType(item.ValueMin, realType);
Expression<Func<object>> minValueLamda = () => minValue;
minExp = Expression.GreaterThanOrEqual(Expression.Property(parameter, item.Name), Expression.Convert(minValueLamda.Body, property.PropertyType));
}
if (item.ValueMax != null)
{
var maxValue = Convert.ChangeType(item.ValueMax, realType);
Expression<Func<object>> maxValueLamda = () => maxValue;
maxExp = Expression.LessThanOrEqual(Expression.Property(parameter, item.Name), Expression.Convert(maxValueLamda.Body, property.PropertyType));
}
if (minExp != null && maxExp != null)
{
expression = Append(expression, Expression.AndAlso(minExp, maxExp));
}
else if (minExp != null)
{
expression = Append(expression, minExp);
}
else if (maxExp != null)
{
expression = Append(expression, maxExp);
}
break;
}
}
}
if (expression == null)
{
return null;
}
return ((Expression<Func<T, bool>>)Expression.Lambda(expression, parameter));
}
}
/// <summary>
/// Defines the <see cref="WhereCondition" />.
/// </summary>
public class WhereCondition
{
/// <summary>
/// Gets or sets the Filters.
/// </summary>
public QueryCollection Filters { get; set; }
/// <summary>
/// Gets or sets the Link.
/// </summary>
public ConditionLink Link { get; set; } = ConditionLink.OrElse;
}