316 lines
14 KiB
C#
316 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
|
|
namespace gehGassi.Common.Data
|
|
{
|
|
/// <summary>
|
|
/// Datamanager Erweiterungen
|
|
/// </summary>
|
|
public static class DataManagerExtensions
|
|
{
|
|
#region EF / Syncfusion Extensions
|
|
|
|
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values)
|
|
{
|
|
var resultExp = CreateMethodCallExpression(source, "OrderBy", ordering);
|
|
return source.Provider.CreateQuery<T>(resultExp);
|
|
}
|
|
|
|
public static IQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string ordering, params object[] values)
|
|
{
|
|
var resultExp = CreateMethodCallExpression(source, "OrderByDescending", ordering);
|
|
return source.Provider.CreateQuery<T>(resultExp);
|
|
}
|
|
|
|
public static IQueryable<T> ThenBy<T>(this IQueryable<T> source, string ordering, params object[] values)
|
|
{
|
|
var resultExp = CreateMethodCallExpression(source, "ThenBy", ordering);
|
|
return source.Provider.CreateQuery<T>(resultExp);
|
|
}
|
|
|
|
public static IQueryable<T> ThenByDescending<T>(this IQueryable<T> source, string ordering, params object[] values)
|
|
{
|
|
var resultExp = CreateMethodCallExpression(source, "ThenByDescending", ordering);
|
|
return source.Provider.CreateQuery<T>(resultExp);
|
|
}
|
|
|
|
private static MethodCallExpression CreateMethodCallExpression<T>(IQueryable<T> source, string methodName, string ordering)
|
|
{
|
|
var strings = ordering.Split('.');
|
|
|
|
var types = new List<Type>();
|
|
var properties = new List<PropertyInfo>();
|
|
var propertyAccesses = new List<MemberExpression>();
|
|
|
|
types.Add(typeof(T));
|
|
|
|
for (int i = 0; i < strings.Length; i++)
|
|
{
|
|
if (i != 0)
|
|
types.Add(properties[i - 1].PropertyType);
|
|
|
|
properties.Add(types[i].GetProperty(strings[i]));
|
|
}
|
|
|
|
var parameter = Expression.Parameter(types[0], "p");
|
|
|
|
for (int i = 0; i < properties.Count; i++)
|
|
{
|
|
propertyAccesses.Add(i == 0
|
|
? Expression.MakeMemberAccess(parameter, properties[i])
|
|
: Expression.MakeMemberAccess(propertyAccesses[i - 1], properties[i]));
|
|
}
|
|
|
|
var orderByExp = Expression.Lambda(propertyAccesses.Last(), parameter);
|
|
|
|
return Expression.Call(typeof(Queryable), methodName,
|
|
new Type[] { types.First(), properties.Last().PropertyType }, source.Expression, Expression.Quote(orderByExp));
|
|
}
|
|
|
|
#region WHERE
|
|
|
|
/// <summary>Generate expression from simple and complex property</summary>
|
|
/// <param name="propertyName"></param>
|
|
/// <param name="sourceType"></param>
|
|
/// <param name="paramExpression"></param>
|
|
/// <returns></returns>
|
|
public static Expression GetValueExpression(this ParameterExpression paramExpression, string propertyName, Type sourceType)
|
|
{
|
|
Expression expression1 = (Expression)null;
|
|
if (typeof(ICustomTypeDescriptor).IsAssignableFrom(sourceType))
|
|
{
|
|
Expression.Convert(paramExpression, typeof(ICustomTypeDescriptor));
|
|
return (Expression<Func<ICustomTypeDescriptor, object, object>>)((ICustomTypeDescriptor t, object o) => t.GetProperties()[propertyName].GetValue(o));
|
|
}
|
|
string str1 = propertyName;
|
|
char[] chArray = new char[1] { '.' };
|
|
foreach (string str2 in str1.Split(chArray))
|
|
{
|
|
if (expression1 != null)
|
|
{
|
|
int result;
|
|
expression1 = !int.TryParse(str2, out result) ? (Expression)Expression.PropertyOrField(expression1, str2) : (Expression)Expression.ArrayIndex(expression1, (Expression)Expression.Constant((object)result));
|
|
}
|
|
else
|
|
{
|
|
Expression expression2 = (Expression)paramExpression;
|
|
if (paramExpression.Type != sourceType)
|
|
expression2 = (Expression)Expression.Convert((Expression)paramExpression, sourceType);
|
|
expression1 = (Expression)Expression.PropertyOrField(expression2, str2);
|
|
}
|
|
}
|
|
return expression1;
|
|
}
|
|
|
|
public static IQueryable Filter(this IQueryable source, string propertyName, object value, FilterType filterType, bool isCaseSensitive, Type sourceType)
|
|
{
|
|
ParameterExpression paramExpression = Expression.Parameter(source.ElementType, sourceType.Name);
|
|
Expression valueExpression = paramExpression.GetValueExpression(propertyName, sourceType);
|
|
Type type = valueExpression.Type;
|
|
//if (Syncfusion.Linq.NullableHelperInternal.IsNullableType(valueExpression.Type))
|
|
// type = NullableHelperInternal.GetUnderlyingType(valueExpression.Type);
|
|
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
|
{
|
|
type = Nullable.GetUnderlyingType(type);
|
|
}
|
|
|
|
if (type == typeof(DateTimeOffset))
|
|
{
|
|
value = DateTimeOffset.Parse(value.ToString());
|
|
}
|
|
else
|
|
value = Convert.ChangeType((object)value, type);
|
|
|
|
if (filterType == FilterType.Equals || filterType == FilterType.NotEquals || (filterType == FilterType.LessThan || filterType == FilterType.LessThanOrEqual) || (filterType == FilterType.GreaterThan || filterType == FilterType.GreaterThanOrEqual))
|
|
{
|
|
BinaryExpression binaryExpression = (BinaryExpression)null;
|
|
switch (filterType)
|
|
{
|
|
case FilterType.LessThan:
|
|
binaryExpression = Expression.LessThan(valueExpression, (Expression)Expression.Constant(value, valueExpression.Type));
|
|
break;
|
|
case FilterType.LessThanOrEqual:
|
|
binaryExpression = Expression.LessThanOrEqual(valueExpression, (Expression)Expression.Constant(value, valueExpression.Type));
|
|
break;
|
|
case FilterType.Equals:
|
|
binaryExpression = !(type != typeof(string)) ? (!isCaseSensitive ? Expression.Equal((Expression)GetToLowerMethodCallExpression(valueExpression), (Expression)Expression.Constant(value == null ? value : (object)value.ToString().ToLower(), valueExpression.Type)) : Expression.Equal(valueExpression, (Expression)Expression.Constant(value, valueExpression.Type))) : Expression.Equal(valueExpression, (Expression)Expression.Constant(value, valueExpression.Type));
|
|
break;
|
|
case FilterType.NotEquals:
|
|
binaryExpression = !(type != typeof(string)) ? (!isCaseSensitive ? Expression.NotEqual((Expression)GetToLowerMethodCallExpression(valueExpression), (Expression)Expression.Constant(value == null ? value : (object)value.ToString().ToLower(), valueExpression.Type)) : Expression.NotEqual(valueExpression, (Expression)Expression.Constant(value, valueExpression.Type))) : Expression.NotEqual(valueExpression, (Expression)Expression.Constant(value, valueExpression.Type));
|
|
break;
|
|
case FilterType.GreaterThanOrEqual:
|
|
binaryExpression = Expression.GreaterThanOrEqual(valueExpression, (Expression)Expression.Constant(value, valueExpression.Type));
|
|
break;
|
|
case FilterType.GreaterThan:
|
|
binaryExpression = Expression.GreaterThan(valueExpression, (Expression)Expression.Constant(value, valueExpression.Type));
|
|
break;
|
|
}
|
|
LambdaExpression lambdaExpression = Expression.Lambda((Expression)binaryExpression, new ParameterExpression[1] { paramExpression });
|
|
return source.Provider.CreateQuery((Expression)Expression.Call(typeof(Queryable), "Where", new Type[1] { source.ElementType }, new Expression[2] { source.Expression, (Expression)lambdaExpression }));
|
|
}
|
|
|
|
MethodInfo method = ((IEnumerable<MethodInfo>)typeof(string).GetMethods()).Where<MethodInfo>((Func<MethodInfo, bool>)(m => m.Name == filterType.ToString())).FirstOrDefault<MethodInfo>();
|
|
Expression body;
|
|
if (isCaseSensitive)
|
|
body = (Expression)Expression.Call(valueExpression, method, new Expression[1]
|
|
{
|
|
(Expression) Expression.Constant(value, typeof (string))
|
|
});
|
|
else
|
|
body = (Expression)Expression.Call((Expression)GetToLowerMethodCallExpression(valueExpression), method, new Expression[1]
|
|
{
|
|
(Expression) Expression.Constant(value == null ? value : (object) value.ToString().ToLower(), typeof (string))
|
|
});
|
|
LambdaExpression lambdaExpression1 = Expression.Lambda(body, new ParameterExpression[1]
|
|
{
|
|
paramExpression
|
|
});
|
|
return source.Provider.CreateQuery((Expression)Expression.Call(typeof(Queryable), "Where", new Type[1] { source.ElementType }, new Expression[2]{source.Expression,(Expression) lambdaExpression1
|
|
}));
|
|
}
|
|
|
|
public static IQueryable Filter(this IQueryable source, string propertyName, object value, FilterType filterType, bool isCaseSensitive)
|
|
{
|
|
Type elementType = source.ElementType;
|
|
return source.Filter(propertyName, value, filterType, isCaseSensitive, elementType);
|
|
}
|
|
|
|
private static MethodCallExpression GetToLowerMethodCallExpression(Expression memExp)
|
|
{
|
|
MethodInfo method = ((IEnumerable<MethodInfo>)typeof(string).GetMethods()).FirstOrDefault<MethodInfo>((Func<MethodInfo, bool>)(m => m.Name == "ToLower"));
|
|
return Expression.Call(memExp, method, new Expression[0]);
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
#region DataManager
|
|
|
|
public static void SetComplexProperties(this DataManager dm, List<ComplexProperty> properties)
|
|
{
|
|
foreach (var complexProperty in properties)
|
|
{
|
|
if (dm?.Sorted?.FirstOrDefault(c => c.Name == complexProperty.Original) != null) dm.Sorted.First(c => c.Name == complexProperty.Original).Name = complexProperty.Complex;
|
|
|
|
//if (dm?.Select?.FindIndex(ind => ind.Equals(complexProperty.Original)) > -1)
|
|
// dm.Select[dm.Select.FindIndex(ind => ind.Equals(complexProperty.Original))] = complexProperty.Complex;
|
|
|
|
if (dm?.Where?.FirstOrDefault(c => c.Field == complexProperty.Original) != null) dm.Where.First(c => c.Field == complexProperty.Original).Field = complexProperty.Complex;
|
|
|
|
if (dm?.Where != null)
|
|
{
|
|
foreach (var whereFilter in dm.Where)
|
|
{
|
|
SetComplexPropertiesForPredicate(whereFilter, complexProperty);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void SetComplexPropertiesForPredicate(WhereFilter whereFilter, ComplexProperty complexProperty)
|
|
{
|
|
if (whereFilter.predicates == null)
|
|
{
|
|
if (whereFilter.Field == complexProperty.Original)
|
|
whereFilter.Field = complexProperty.Complex;
|
|
}
|
|
else
|
|
{
|
|
foreach (var predicate in whereFilter.predicates)
|
|
{
|
|
SetComplexPropertiesForPredicate(predicate, complexProperty);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static IQueryable<T> ApplySorting<T>(this DataManager dm, IQueryable<T> source)
|
|
{
|
|
if (dm.Sorted != null && dm.Sorted.Count > 0)
|
|
{
|
|
var count = 0;
|
|
foreach (var sort in dm.Sorted)
|
|
{
|
|
if (count == 0)
|
|
source = sort.Direction.ToLower() == "ascending" ? source.OrderBy(sort.Name.ToPascalCase()) : source.OrderByDescending(sort.Name.ToPascalCase());
|
|
else
|
|
source = sort.Direction.ToLower() == "ascending" ? source.ThenBy(sort.Name.ToPascalCase()) : source.ThenByDescending(sort.Name.ToPascalCase());
|
|
count += 1;
|
|
}
|
|
}
|
|
return source;
|
|
}
|
|
|
|
public static IQueryable<T> ApplyFiltering<T>(this DataManager dm, IQueryable<T> source, out int totalCount)
|
|
{
|
|
totalCount = 0;
|
|
|
|
if (dm.Where != null)
|
|
{
|
|
foreach (var whereFilter in dm.Where)
|
|
{
|
|
whereFilter.Field = whereFilter.Field.ToPascalCase();
|
|
source = HandlePredicate(whereFilter, source);
|
|
}
|
|
}
|
|
totalCount = source.Count();
|
|
return source;
|
|
}
|
|
|
|
public static IQueryable<T> HandlePredicate<T>(WhereFilter whereFilter, IQueryable<T> source)
|
|
{
|
|
if (whereFilter.predicates == null)
|
|
{
|
|
var filter = GetFilterOperator(whereFilter.Operator);
|
|
var filterType = (FilterType)Enum.Parse(typeof(FilterType), filter, true);
|
|
if (whereFilter.value != null)
|
|
source = (IQueryable<T>)source.Filter(whereFilter.Field, whereFilter.value, filterType, false);
|
|
}
|
|
else
|
|
{
|
|
foreach (var predicate in whereFilter.predicates)
|
|
{
|
|
source = HandlePredicate<T>(predicate, source);
|
|
}
|
|
}
|
|
return source;
|
|
}
|
|
|
|
private static string GetFilterOperator(string filter)
|
|
{
|
|
if (filter == "equal")
|
|
filter = "equals";
|
|
else if (filter == "notequal")
|
|
filter = "notequals";
|
|
return filter;
|
|
}
|
|
|
|
public static IQueryable<T> ApplyPaging<T>(this DataManager dm, IQueryable<T> source)
|
|
{
|
|
if (dm.Skip != 0)
|
|
{
|
|
source = (IQueryable<T>)source.Skip<T>(dm.Skip);
|
|
}
|
|
if (dm.Take != 0)
|
|
{
|
|
source = (IQueryable<T>)source.Take<T>(dm.Take);
|
|
}
|
|
return source;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Custom
|
|
|
|
|
|
|
|
#endregion
|
|
}
|
|
}
|