jquery - jqGrid 的 LINQ 搜索中的可为 Null 值

标签 jquery asp.net-mvc linq jqgrid linq-extensions

首先,抱歉我的英语不好,这不是我的母语。

我在工作中的 ASP.NET MVC 项目中使用 jqgrid,在实现搜索时遇到一些问题。 我尝试使用一种在互联网上使用 LinqExtensions 找到的解决方案。当实体具有可为空值时,就会出现问题,例如:

public class MyClass()
{
   string StringValue { get; set; }
   int? IntegerValue { get; set; }
}

这是因为在数据库中,值接受 null,并且由于项目中的其他原因,我的 C# 代码中需要可空值。

在另一个名为 LinqExtensions 的类中,where 子句如下所示:

public static IQueryable<T> Where<T>(this IQueryable<T> source, string searchProperty, string searchString, string searchOper)
{
        Type type = typeof(T);

        if (string.IsNullOrEmpty(searchString))
            return source;

        ConstantExpression searchFilter = Expression.Constant(searchString.ToUpper());

        ParameterExpression parameter = Expression.Parameter(type, "p");
        //PropertyInfo property = type.GetProperty(searchProperty);
        //Expression propertyAccess = Expression.MakeMemberAccess(parameter, property);

        MemberExpression memberAccess = null;
        String[] separador = {"__"};
        foreach (var property2 in searchProperty.Split(separador, StringSplitOptions.None))
            memberAccess = MemberExpression.Property
               (memberAccess ?? (parameter as Expression), property2);
        Expression propertyAccess = memberAccess;

        if (propertyAccess.Type == typeof(Nullable<DateTime>))
        {
            PropertyInfo valProp = typeof(Nullable<DateTime>).GetProperty("Value");
            propertyAccess = Expression.MakeMemberAccess(propertyAccess, valProp);
            Nullable<DateTime> tn = DateTime.Parse(searchString);
            searchFilter = Expression.Constant(tn);
        }


        //support int?
        if (propertyAccess.Type == typeof(Nullable<Char>))
        {
            PropertyInfo valProp = typeof(Nullable<Char>).GetProperty("Value");
            propertyAccess = Expression.MakeMemberAccess(propertyAccess, valProp);
            Nullable<Char> tn = Char.Parse(searchString);
            searchFilter = Expression.Constant(tn);
        }

        if (propertyAccess.Type == typeof(Nullable<Int16>))
        {
            PropertyInfo valProp = typeof(Nullable<Int16>).GetProperty("Value");
            propertyAccess = Expression.MakeMemberAccess(propertyAccess, valProp);
            Nullable<Int16> tn = Int16.Parse(searchString);
            searchFilter = Expression.Constant(tn);
        }

        if (propertyAccess.Type == typeof(Nullable<Int32>))
        {
            PropertyInfo valProp = typeof(Nullable<Int32>).GetProperty("Value");
            propertyAccess = Expression.MakeMemberAccess(propertyAccess, valProp);
            Nullable<Int32> tn = Int32.Parse(searchString);
            searchFilter = Expression.Constant(tn);
        }

        if (propertyAccess.Type == typeof(Nullable<Int64>))
        {
            PropertyInfo valProp = typeof(Nullable<Int64>).GetProperty("Value");
            propertyAccess = Expression.MakeMemberAccess(propertyAccess, valProp);
            Nullable<Int64> tn = Int64.Parse(searchString);
            searchFilter = Expression.Constant(tn);
        }

        //support decimal?
        if (propertyAccess.Type == typeof(Nullable<decimal>))
        {
            PropertyInfo valProp = typeof(Nullable<decimal>).GetProperty("Value");
            propertyAccess = Expression.MakeMemberAccess(propertyAccess, valProp);

            Nullable<decimal> tn = Decimal.Parse(searchString);
            searchFilter = Expression.Constant(tn);
        }

        if (propertyAccess.Type == typeof(Char))
            searchFilter = Expression.Constant(Char.Parse(searchString));

        if (propertyAccess.Type == typeof(Int16))
            searchFilter = Expression.Constant(Int16.Parse(searchString));

        if (propertyAccess.Type == typeof(Int32))
            searchFilter = Expression.Constant(Int32.Parse(searchString));

        if (propertyAccess.Type == typeof(Int64))
            searchFilter = Expression.Constant(Int64.Parse(searchString));

        if (propertyAccess.Type == typeof(decimal))
            searchFilter = Expression.Constant(Decimal.Parse(searchString));

        if (propertyAccess.Type == typeof(DateTime))
            searchFilter = Expression.Constant(DateTime.Parse(searchString));


        MethodInfo startsWith = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
        MethodInfo endsWith = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });
        MethodInfo contains = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });

        //MethodInfo contains = typeof(Int32Extensions).GetMethod("Contains", new Type[] { typeof(Int64), typeof(Int64) });

        Expression operation = null;

        switch (searchOper)
        {
            default:
            case "eq":
                operation = Expression.Equal(propertyAccess, searchFilter);
                break;
            case "ne":
                operation = Expression.NotEqual(propertyAccess, searchFilter);
                break;
            case "lt":
                operation = Expression.LessThan(propertyAccess, searchFilter);
                break;
            case "le":
                operation = Expression.LessThanOrEqual(propertyAccess, searchFilter);
                break;
            case "gt":
                operation = Expression.GreaterThan(propertyAccess, searchFilter);
                break;
            case "ge":
                operation = Expression.GreaterThanOrEqual(propertyAccess, searchFilter);
                break;
            case "bw":
                operation = Expression.Call(propertyAccess, startsWith, searchFilter);
                break;
            case "bn":
                operation = Expression.Call(propertyAccess, startsWith, searchFilter);
                operation = Expression.Not(operation);
                break;
            case "ew":
                operation = Expression.Call(propertyAccess, endsWith, searchFilter);
                break;
            case "en":
                operation = Expression.Call(propertyAccess, endsWith, searchFilter);
                operation = Expression.Not(operation);
                break;
            case "cn":
                operation = Expression.Call(propertyAccess, contains, searchFilter);
                break;
            case "nc":
                operation = Expression.Call(propertyAccess, contains, searchFilter);
                operation = Expression.Not(operation);
                break;
        }

        var whereExpression = Expression.Lambda(operation, parameter);

        var resultExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { source.ElementType }, source.Expression, whereExpression);

        return source.Provider.CreateQuery<T>(resultExpression);
    }

Model类中的方法是:

public JsonResult GetData(GridSettings grid)
    {
        if (Session["SomeValue"] != null)
        {
            var query = (new GridModel()).GetQuery();

            //Filters
            if (grid.IsSearch && grid.Where != null)
            {
                //And
                if (grid.Where.groupOp == "AND")
                    foreach (var rule in grid.Where.rules)
                        query = query.Where<MyClass>(rule.field, rule.data.ToUpper(), rule.op);
                else
                {
                    //Or
                    var temp = (new List<MyClass>()).AsQueryable();
                    foreach (var rule in grid.Where.rules)
                    {
                        var t = query.Where<MyClass>(rule.field, rule.data, rule.op);
                        temp = temp.Concat<MyClass>(t);
                    }
                    //Clean repeat elements
                    query = temp.Distinct<MyClass>();
                }
            }
            //Order
            query = query.OrderBy<MyClass>(grid.SortColumn,
                grid.SortOrder);
            //Count
            var count = query.Count();
            //Pager
            var data = query.Skip((grid.PageIndex - 1) * grid.PageSize).Take(grid.PageSize).ToArray();

            //Convert
            var result = new
            {
                .
                .
                .
            }
  }

我创建网格,非常正确地显示值,但是......当按字符串搜索时,即使某些值为空,也会出现任何问题,并且如果尝试按 IntegerValue (支持 null)进行搜索,并且当某些值出现时会抛出异常实体为空。这个问题让我变成了一个疯子。

如果有人有同样的问题或知道如何解决,我将永远感激

再见

最佳答案

它比我想象的更容易,最好的方法是重写表达式调用的运算符:

例如,在我的问题中,将 equals 方法重写为:

    private static Expression LinqEqual(Expression e1, Expression e2)
    {
        if (IsNullableType(e1.Type) && !IsNullableType(e2.Type))
            e2 = Expression.Convert(e2, e1.Type);
        else if (!IsNullableType(e1.Type) && IsNullableType(e2.Type))
            e1 = Expression.Convert(e1, e2.Type);
        return Expression.Equal(e1, e2);
    }

    private static bool IsNullableType(Type t)
    {
        return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

并替换这段代码:

Expression operation = null;

    switch (searchOper)
    {
        default:
        case "eq":
            operation = Expression.Equal(propertyAccess, searchFilter);
            break;
        .
        .
        .
    }

希望问题和解决方案对某人有所帮助。

感谢 Stackoverflow

关于jquery - jqGrid 的 LINQ 搜索中的可为 Null 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6331499/

相关文章:

c# - 从数据库模型填充 View 模型但出现对象引用错误

c# - 打开Excel xlsx文件进行查看

javascript - CKEditor checkDirty() 在源代码编辑区域

Javascript 时间选择器不工作

javascript - 在 asp.net MVC 中提交局部 View 时如何显示加载微调器?

c# - 我如何将代码更改为linq样式

linq - 比较两个集合

entity-framework - 以实体属性作为参数的 EF 自定义选择

javascript - 从 td 获取列号

javascript - 在相同的结构中找到下一个文本区域