jqGrid 的 LINQ 搜索中的可为 Null 值
首先,抱歉我的英语不好,这不是我的母语。
我在工作中的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
它比我想象的更容易,最好的方法是重写表达式调用的运算符:
例如在我的问题中,重写 equals 方法为:
并替换代码段:
我希望问题和解决方案对某人有所帮助。
感谢 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:
and replace the piece of code:
I hope the problem and solution help some one.
Thanks Stackoverflow