jqGrid 的 LINQ 搜索中的可为 Null 值

发布于 2024-11-15 07:54:42 字数 8635 浏览 5 评论 0原文

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

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

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

这是因为在数据库中,值接受空值,并且出于项目中的其他原因,需要在我的 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)进行搜索,当实体上的某些值为 null 时,会抛出异常。这个问题让我变成了一个疯子。

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

再见

first of all, sorry for my bad english, isnt my native language.

Im using jqgrid on a ASP.NET MVC project on my work, and have some problems when implement search.
Im try to use one solution that find on internet using LinqExtensions. The problem ocurres when the entity have nullable value like:

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

This is because in the database the values accepts null, and need the nullable values on my c# code for other reasons on the project.

In another class named LinqExtensions the where clause is like this:

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);
    }

The method in Model class is:

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
            {
                .
                .
                .
            }
  }

I create the grid, display values very correctly but... when search by string any problem ocurres even if some values are null, and if trying to search by the IntegerValue (that supports null) and Exception throws when some values on entity are null. This problem being transform me on a crazy man.

Please, if any have the same problem or know how to solve it, i will be eternally grateful

Bye

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

dawn曙光 2024-11-22 07:54:42

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

例如在我的问题中,重写 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

Its more easy than i think, the best way is to override the operator called for the expression:

For example in my problem, override the equals method to:

    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<>);
    }

and replace the piece of code:

Expression operation = null;

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

I hope the problem and solution help some one.

Thanks Stackoverflow

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文