When param.SearchValue == string.Empty
Count()
works. But in other cases Count()
or any other execution doesn't work, throwing the exception:
must be reducible node
Here's my code :
public DataTableReturnValue<T> setParameter<T>(DataTableParameters param, IQueryable<T> query) where T : class
{
var columnNameList = JsonConvert.DeserializeObject<List<ColumnName>>(param.columnName).Select(x => x.data).ToList();
int totalrows = query.Count();
Expression<Func<T, bool>> expressionCombine = DataTableExpressions.ContainsExp<T>(columnNameList.First(), param.SearchValue);
if (param.SearchValue != string.Empty)
{
int i = 0;
foreach (string ColumnNameItem in columnNameList)
{
if (i != 0)
{
var predicate = DataTableExpressions.ContainsExp<T>(ColumnNameItem, param.SearchValue);
expressionCombine = DataTableExpressions.AppendExpression(expressionCombine, predicate);
}
i++;
}
}
query = query.Where(expressionCombine);
int totalrowsafterfiltering = query.Count();
query = query.OrderBy(param.SortColumnName + " " + param.SortDirection);
if (param.Length != -1)
query = query.Skip(param.StartValue).Take(param.Length);
return (new DataTableReturnValue<T> { data = query.ToList(), draw = param.Draw, recordsTotal = totalrows, recordsFiltered = totalrowsafterfiltering });
}
public class DataTableReturnValue<T> where T :class
{
public List<T> data{ get; set; }
public int recordsTotal { get; set; }
public int recordsFiltered { get; set; }
public string draw { get; set; }
}
public class DataTableParameters
{
public string SearchValue { get; set; }
public int StartValue { get; set; }
public int Length { get; set; }
public string SortColumnName { get; set; }
public string SortDirection { get; set; }
public string Draw { get; set; }
public int application_id { get; set; }
public string columnName { get; set; }
public int user_id { get; set; }
}
My goal is to create a dynamic query. columnNameList
returns the headers I use in the datatable. And I create a IQueryable query by adding OrElse
to these headers with the foreach (string ColumnNameItem in columnNameList)
loop. It doesn't execute query = query.Where(expressionCombine);
after exiting this cycle.
And these are the expression methods :
public static class DataTableExpressions
{
public static Expression<Func<T, bool>> ContainsExp<T>(string propertyName, string contains)
{
var propertyType = typeof(T).GetProperty(propertyName).PropertyType;
var parameterExp = Expression.Parameter(typeof(T), "type");
Expression propertyExp = Expression.Property(parameterExp, propertyName);
if (propertyType == typeof(int) || propertyType == typeof(int?))
{
propertyExp = Expression.Convert(propertyExp, typeof(double?));
var stringConvertMethod = typeof(SqlFunctions).GetMethod("StringConvert", new[] { typeof(double?) });
propertyExp = Expression.Call(stringConvertMethod, propertyExp);
}
else if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))
{
propertyExp = Expression.Convert(propertyExp, typeof(DateTime?));
var stringConvertMethod = typeof(SqlFunctions).GetMethod("StringConvert", new[] { typeof(DateTime?) });
propertyExp = Expression.Call(stringConvertMethod, propertyExp);
}
var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var someValue = Expression.Constant(contains, typeof(string));
var containsMethodExp = Expression.Call(propertyExp, method, someValue);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
}
public static Expression<Func<T, bool>> AppendExpression<T>(Expression<Func<T, Boolean>> left, Expression<Func<T, Boolean>> right)
{
Expression<Func<T, bool>> result;
result = OrElse(left, right);
return result;
}
public static Expression<Func<T, bool>> OrElse<T>(Expression<Func<T, Boolean>> left, Expression<Func<T, Boolean>> right)
{
Expression<Func<T, Boolean>> combined = Expression.Lambda<Func<T, Boolean>>(
Expression.OrElse(
left.Body,
new ExpressionParameterReplacer(right.Parameters, left.Parameters).Visit(right.Body)
), left.Parameters);
return combined;
}
}
public class ExpressionParameterReplacer : ExpressionVisitor
{
private IDictionary<ParameterExpression, ParameterExpression> ParameterReplacements { get; set; }
public ExpressionParameterReplacer(IList<ParameterExpression> fromParameters, IList<ParameterExpression> toParameters)
{
ParameterReplacements = new Dictionary<ParameterExpression, ParameterExpression>();
for (int i = 0; i != fromParameters.Count && i != toParameters.Count; i++)
{ ParameterReplacements.Add(fromParameters[i], toParameters[i]); }
}
protected override Expression VisitParameter(ParameterExpression node)
{
ParameterExpression replacement;
if (ParameterReplacements.TryGetValue(node, out replacement))
{ node = replacement; }
return base.VisitParameter(node);
}
}