jqGrid使用Oleg的例子过滤记录

时间:2013-03-18 13:51:04

标签: asp.net-mvc search jqgrid filtering

我在使用网格中的两个列解决几个错误时遇到了问题。我创建了一个包含几个表的示例数据库,并创建了一个jqGrid测试应用程序来显示数据。我想对网格上的数据进行一些搜索/过滤。我使用了Oleg的MVC搜索和过滤示例。我的前两列(ID,事件标题)工作得很完美,但之后的任何专栏都不起作用。我确信我错过了一些东西,却看不到我错过的东西。任何帮助都会很棒。以下是代码。

客户端:

var myGrid = $('#list'),
    decodeErrorMessage = function (jqXHR, textStatus, errorThrown) {
                var html, errorInfo, i, errorText = textStatus + '\n' + errorThrown;
                if (jqXHR.responseText.charAt(0) === '[') {
                    try {
                        errorInfo = $.parseJSON(jqXHR.responseText);
                        errorText = "";
                        for (i = 0; i < errorInfo.length; i++) {
                            if (errorText.length !== 0) {
                                errorText += "<hr />";
                            }
                            errorText += errorInfo[i].Source + ": " + errorInfo[i].Message;
                        }
                    }
                    catch (e) { }
                } else {
                    html = /<body.*?>([\s\S]*)<\/body>/.exec(jqXHR.responseText);
                    if (html !== null && html.length > 1) {
                        errorText = html[1];
                    }
                }
                return errorText;
            };

        myGrid.jqGrid({
            url: '../Admin/GetEventsGridData/',
            datatype: 'json',
            mtype: 'POST',
            colNames: ['ID', 'Event Title', 'Series', 'Occ', 'Department' ],  
            colModel: [
                        { name: 'EVENT_ID', index: 'EVENT_ID', editable: true, editoptions: { readonly: 'readonly' }, width: 25, searchoptions: { sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge']} },
                        { name: 'EVENT_TITLE', index: 'EVENT_TITLE', editable: true, width: 205, searchoptions: { sopt: ['cn', 'nc', 'bw', 'bn', 'eq', 'ne', 'ew', 'en', 'lt', 'le', 'gt', 'ge']} },
                        { name: 'SERIES_DESCRIPTION', index: 'SERIES_DESCRIPTION', editable: true, width: 30, searchoptions: { sopt: ['cn', 'nc', 'bw', 'bn', 'eq', 'ne', 'ew', 'en', 'lt', 'le', 'gt', 'ge']} },
                        { name: 'OCCURRENCES', index: 'OCCURRENCES', editable: true, width: 20, searchoptions: { sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge']} }
                        { name: 'DEPARTMENT_NAME', index: 'DEPARTMENT_NAME', editable: true, width: 100, searchoptions: { sopt: ['cn', 'nc', 'bw', 'bn', 'eq', 'ne', 'ew', 'en', 'lt', 'le', 'gt', 'ge']} }
                        ],
            pager: '#pager',
            autowidth: true,
            height: 'auto',
            rowNum: 10,
            rowList: [5, 10, 20, 50],
            sortname: 'EVENT_ID',
            sortorder: "desc",
            viewrecords: true,
            caption: 'Events',
            jsonReader: { cell: "" },
            loadError: function (jqXHR, textStatus, errorThrown) {
                // remove error div if exist
                $('#' + this.id + '_err').remove();
                // insert div with the error description before the grid
                myGrid.closest('div.ui-jqgrid').before(
                    '<div id="' + this.id + '_err" style="max-width:' + this.style.width +
                    ';"><div class="ui-state-error ui-corner-all" style="padding:0.7em;float:left;"><span class="ui-icon ui-icon-alert" style="float:left; margin-right: .3em;"></span><span style="clear:left">' +
                    decodeErrorMessage(jqXHR, textStatus, errorThrown) + '</span></div><div style="clear:left" /></div>')
            },
            loadComplete: function () {
                // remove error div if exist
                $('#' + this.id + '_err').remove();
            }
        });
        myGrid.jqGrid('navGrid', '#pager', { add: true, edit: true, del: true, refresh: true },
                      updateDialog, // add a record
                      updateDialog, // edit a record
                      updateDialog, // delete a record
                      {multipleSearch: true, overlay: false, width: 460 });
        myGrid.jqGrid('filterToolbar', { stringResult: true, searchOnEnter: true, defaultSearch: 'cn' });
        myGrid.jqGrid('navButtonAdd', '#pager',
                    { caption: "Filter", title: "Toggle Searching Toolbar",
                        buttonicon: 'ui-icon-pin-s',
                        onClickButton: function () { myGrid[0].toggleToolbar(); }
                    });

这是我的服务器端:

using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using Newtonsoft.Json;
//using System.Data.Entity.Infrastructure;
using CATS.Models;

namespace CATS.Controllers
{
// to send exceptions as json we define [HandleJsonException] attribute
public class ExceptionInformation
{
    public string Message { get; set; }

    public string Source { get; set; }

    public string StackTrace { get; set; }
}

public class HandleJsonExceptionAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null)
        {
            filterContext.HttpContext.Response.StatusCode =
                (int)System.Net.HttpStatusCode.InternalServerError;

            var exInfo = new List<ExceptionInformation>();
            for (Exception ex = filterContext.Exception; ex != null; ex = ex.InnerException)
            {
                PropertyInfo propertyInfo = ex.GetType().GetProperty("ErrorCode");
                exInfo.Add(new ExceptionInformation()
                {
                    Message = ex.Message,
                    Source = ex.Source,
                    StackTrace = ex.StackTrace
                });
            }
            filterContext.Result = new JsonResult() { Data = exInfo };
            filterContext.ExceptionHandled = true;
        }
    }
}

public class Filters
{
    public enum GroupOp
    {
        AND,
        OR
    }
    public enum Operations
    {
        eq, // "equal"
        ne, // "not equal"
        lt, // "less"
        le, // "less or equal"
        gt, // "greater"
        ge, // "greater or equal"
        bw, // "begins with"
        bn, // "does not begin with"
        //in, // "in"
        //ni, // "not in"
        ew, // "ends with"
        en, // "does not end with"
        cn, // "contains"
        nc  // "does not contain"
    }
    public class Rule
    {
        public string field { get; set; }
        public Operations op { get; set; }
        public string data { get; set; }
    }

    public GroupOp groupOp { get; set; }
    public List<Rule> rules { get; set; }
    private static readonly string[] FormatMapping = {
        "(it.{0} = @p{1})",                 // "eq" - equal
        "(it.{0} <> @p{1})",                // "ne" - not equal
        "(it.{0} < @p{1})",                 // "lt" - less than
        "(it.{0} <= @p{1})",                // "le" - less than or equal to
        "(it.{0} > @p{1})",                 // "gt" - greater than
        "(it.{0} >= @p{1})",                // "ge" - greater than or equal to
        "(it.{0} LIKE (@p{1}+'%'))",        // "bw" - begins with
        "(it.{0} NOT LIKE (@p{1}+'%'))",    // "bn" - does not begin with
        "(it.{0} LIKE ('%'+@p{1}))",        // "ew" - ends with
        "(it.{0} NOT LIKE ('%'+@p{1}))",    // "en" - does not end with
        "(it.{0} LIKE ('%'+@p{1}+'%'))",    // "cn" - contains
        "(it.{0} NOT LIKE ('%'+@p{1}+'%'))" //" nc" - does not contain
    };
    internal ObjectQuery<T> FilterObjectSet<T>(ObjectQuery<T> inputQuery) where T : class
    {
        if (rules.Count <= 0)
            return inputQuery;

        var sb = new StringBuilder();
        var objParams = new List<ObjectParameter>(rules.Count);

        foreach (Rule rule in rules)
        {
            PropertyInfo propertyInfo = typeof(T).GetProperty(rule.field);
            if (propertyInfo == null)
                continue; // skip wrong entries

            if (sb.Length != 0)
                sb.Append(groupOp);

            var iParam = objParams.Count;
            sb.AppendFormat(FormatMapping[(int)rule.op], rule.field, iParam);

            ObjectParameter param;
            switch (propertyInfo.PropertyType.FullName)
            {
                case "System.Int32":  // int
                    param = new ObjectParameter("p" + iParam, Int32.Parse(rule.data));
                    break;
                case "System.Int64":  // bigint
                    param = new ObjectParameter("p" + iParam, Int64.Parse(rule.data));
                    break;
                case "System.Int16":  // smallint
                    param = new ObjectParameter("p" + iParam, Int16.Parse(rule.data));
                    break;
                case "System.SByte":  // tinyint
                    param = new ObjectParameter("p" + iParam, SByte.Parse(rule.data));
                    break;
                case "System.Single": // Edm.Single, in SQL: float
                    param = new ObjectParameter("p" + iParam, Single.Parse(rule.data));
                    break;
                case "System.Double": // float(53), double precision
                    param = new ObjectParameter("p" + iParam, Double.Parse(rule.data));
                    break;
                case "System.Boolean": // Edm.Boolean, in SQL: bit
                    param = new ObjectParameter("p" + iParam,
                        String.Compare(rule.data, "1", StringComparison.Ordinal) == 0 ||
                        String.Compare(rule.data, "yes", StringComparison.OrdinalIgnoreCase) == 0 ||
                        String.Compare(rule.data, "true", StringComparison.OrdinalIgnoreCase) == 0);
                    break;
                default:
                    // TODO: Extend to other data types
                    // binary, date, datetimeoffset,
                    // decimal, numeric,
                    // money, smallmoney
                    // and so on

                    param = new ObjectParameter("p" + iParam, rule.data);
                    break;
            }
            objParams.Add(param);
        }

        ObjectQuery<T> filteredQuery = inputQuery.Where(sb.ToString());
        foreach (var objParam in objParams)
            filteredQuery.Parameters.Add(objParam);

        return filteredQuery;
    }
}

[HandleJsonException]
public class AdminController : Controller
{
    //
    // GET: /Admin/

    public ActionResult Admin()
    {
        ViewBag.PageTitle = "Admin";

        return View();
    }

    public ActionResult GetEventsGridData(string sidx, string sord, int page, int rows, bool _search, string filters)
    {
        var context = new CATEntities();

        //var context = new CATContext();
        //var serializer = new JavaScriptSerializer();

        //var objectContext = ((IObjectContextAdapter)context).ObjectContext;
        //var eventset = objectContext.CreateObjectSet<EVENT>();

        Filters f = (!_search || string.IsNullOrEmpty(filters)) ? null : JsonConvert.DeserializeObject<Filters>(filters);
        ObjectQuery<EVENT> filteredQuery = (f == null ? context.EVENT : f.FilterObjectSet(context.EVENT)); // (ObjectQuery<EVENT>)eventset)
        filteredQuery.MergeOption = MergeOption.NoTracking; // we don't want to update the data

        var totalRecords = filteredQuery.Count();

        var pagedQuery = filteredQuery.Skip("it." + sidx + " " + sord, "@skip",
                                            new ObjectParameter("skip", (page - 1) * rows))
                                     .Top("@limit", new ObjectParameter("limit", rows));

        // to be able to use ToString() below which does NOT exist in the LINQ to Entity
        var queryDetails = (from item in pagedQuery
                            select new { item.EVENT_ID, item.EVENT_TITLE, item.EVENT_SERIES.SERIES_DESCRIPTION, item.OCCURRENCES, item.DEPARTMENT.DEPARTMENT_NAME  }).ToList();


        return Json(new
        {
            total = (totalRecords + rows - 1) / rows,
            page,
            records = totalRecords,
            rows = (from item in queryDetails
                    select new[] {
                            item.EVENT_ID.ToString(),
                            item.EVENT_TITLE,
                            item.SERIES_DESCRIPTION,
                            item.OCCURRENCES.ToString()
                            item.DEPARTMENT_NAME
                    }).ToList()
        });
    }

    public ActionResult UpdateGridData(FormCollection formCollection)
    {
        return Json(JsonRequestBehavior.AllowGet);
    }
}

}

我的问题是我在Occurrences列上收到此错误:

System.Data.Entity: The argument types 'Edm.Int32' and 'Edm.String' are incompatible for this operation. Near equals expression, line 6, column 17.

Occurrences列中的所有数据都是Integer数据。这告诉我它正在寻找Integer数据,但我发送的是String数据。此列与EVENT_ID列类似。不知道我在哪里错过了断开连接。

系列列也有问题。在Event表上,Series列是我的系列表的外键ID。从那里我得到系列描述。部门栏目类似。当我尝试对这两列进行搜索/过滤时,我收到此错误:

System.Data.Entity: You must specify a valid predicate for filtering the results. Parameter name: predicate

我错过了一些东西,但对于我的生活,我无法找到它。

1 个答案:

答案 0 :(得分:0)

尝试此代码....

数据是实体的集合...... cols是List Entity.PropertyName

var filterExpr = jqGridHelper.SearchDelgate(filters,cols);

var data = EntityRepository.Get()。Where(filterExpr).ToList();

    public static Expression<Func<T, bool>> SearchDelgate<T>(string jsonData, List<JqGridColModel> colmodels) where T : Entity
    {
        var dateCols = colmodels.Where(x => x.colType == "System.DateTime").Select(x => x.index).ToList();
        var filter = GetFilter(jsonData, dateCols);
        return GetFilterExpr<T>(filter, null, null);
    }
    private static Expression<Func<T, bool>> GetFilterExpr<T>(JqGridFilter filter, string searchOpr, Expression<Func<T, bool>> expr) where T : Entity
    {
        var rules = filter.rules;
        searchOpr = searchOpr ?? GetOperator(filter.groupOp);
        Expression<Func<T, bool>> ruleexpr = null;
        rules.ForEach(x =>
        {
            ruleexpr = Extentions.ToExpression<T>(GetOperator(filter.groupOp), x.field, GetOperator(x.op), x.data, ruleexpr);
        });
        if (!expr.IsNull())
            ruleexpr = searchOpr == "&&" ? expr.And(ruleexpr) : expr.Or(ruleexpr);
        if (!filter.groups.IsNull())
        {
            Expression<Func<T, bool>> groupexpr = null;
            filter.groups.ForEach(x =>
            {
                groupexpr = GetFilterExpr<T>(x, searchOpr, groupexpr);
            });
            expr = searchOpr == "&&" ? ruleexpr.And(groupexpr) : ruleexpr.Or(groupexpr);
        }
        else
            expr = ruleexpr;
        return expr;
    }

    private static JqGridFilter GetFilter(string jsonData, List<string> dateCols)
    {
        var temp = Deserialize<Dictionary<string, object>>(jsonData);
        return CreateFilter(temp, dateCols);
    }
    private static JqGridFilter CreateFilter(object rawData, List<string> dateCols)
    {
        var temp = rawData.ExplicitCast<Dictionary<string, object>>();
        var groupOp = temp["groupOp"];
        var rulesData = temp["rules"];
        var groupsdata = temp.Keys.Contains("groups") ? temp["groups"] : null;

        JqGridFilter filter = new JqGridFilter();
        filter.groupOp = groupOp.ToString();
        var rules = new List<JqGridFilterRule>();
        foreach (var obj in rulesData.ExplicitCast<ArrayList>())
        {
            JqGridFilterRule rule = new Core.JqGridFilterRule();
            rule.DictToObject(obj);
            setDateCols(rule, rules, dateCols);
            // rules.Add(rule);
        }
        if (!rules.IsNull())
            filter.rules = rules;

        if (!groupsdata.IsNull())
        {
            var groups = new List<JqGridFilter>();
            foreach (var obj in groupsdata.ExplicitCast<ArrayList>())
            {
                groups.Add(CreateFilter(obj, dateCols));
            }
            if (!groups.IsNull())
                filter.groups = groups;
        }
        return filter;
    }
    private static string GetOperator(string op)
    {
        string searchOper = "==";
        switch (op)
        {
            case "eq":  //equals
            case "ew":  //equals with
                searchOper = "=="; break;
            case "ne": //notequal
                searchOper = "!="; break;
            //case "bw": //begins with
            //    searchOper = "=="; break;
            //case "bn": //does not begin with
            //    searchOper = "=="; break;
            //case "en": //does not ends with
            //    searchOper = "=="; break;
            case "cn": //contains
                searchOper = "LIKE"; break;
            case "nc": //does not contains
                searchOper = "NOTLIKE"; break;
            //case "nu": //is null
            //    searchOper = "=="; break;
            //case "nn": //is not null
            //searchOper = "=="; break;
            //case "in": //is in 
            //    searchOper = "=="; break;
            //case "ni": //is not in
            //    searchOper = "=="; break;
            case "lt": //less
                searchOper = "<"; break;
            case "le": //less or equal
                searchOper = "<="; break;
            case "gt": //greater
                searchOper = ">"; break;
            case "ge": //greater or equal
                searchOper = ">="; break;
            case "AND": //greater or equal
                searchOper = "&&"; break;
            case "OR": //greater or equal
                searchOper = "||"; break;
            default:
                searchOper = "=="; break;
        }
        return searchOper;
    }

    private static void setDateCols(JqGridFilterRule obj, List<JqGridFilterRule> rules, List<string> dateCols)
    {
        if (dateCols.Contains(obj.field) && obj.op == "eq")
        {
            JqGridFilterRule obj_ge = new JqGridFilterRule();
            obj_ge.field = obj.field;
            obj_ge.op = "ge";
            obj_ge.data = Convert.ToDateTime(obj.data).ToShortDateString();

            JqGridFilterRule obj_lt = new JqGridFilterRule();
            obj_lt.field = obj.field;
            obj_lt.op = "lt";
            obj_lt.data = Convert.ToDateTime(obj.data).AddDays(1).ToShortDateString();

            rules.Add(obj_lt);
            rules.Add(obj_ge);
        }
        else
            rules.Add(obj);
    }
public static Expression<Func<T, bool>> ToExpression<T>(string andOrOperator, string propName, string opr, string value, Expression<Func<T, bool>> expr = null)
    {
        Expression<Func<T, bool>> func = null;
        try
        {
            ParameterExpression paramExpr = Expression.Parameter(typeof(T));
            var arrProp = propName.Split('.').ToList();
            Expression binExpr = null;
            string partName = string.Empty;
            arrProp.ForEach(x =>
            {
                Expression tempExpr = null;
                partName = partName.IsNull() ? x : partName + "." + x;
                if (partName == propName)
                {
                    var member = NestedExprProp(paramExpr, partName);
                    var type = member.Type.Name == "Nullable`1" ? Nullable.GetUnderlyingType(member.Type) : member.Type;
                    tempExpr = ApplyFilter(opr, member, Expression.Convert(ToExprConstant(type, value), member.Type));
                }
                else
                    tempExpr = ApplyFilter("!=", NestedExprProp(paramExpr, partName), Expression.Constant(null));
                if (binExpr != null)
                    binExpr = Expression.AndAlso(binExpr, tempExpr);
                else
                    binExpr = tempExpr;
            });
            Expression<Func<T, bool>> innerExpr = Expression.Lambda<Func<T, bool>>(binExpr, paramExpr);
            if (expr != null)
                innerExpr = (andOrOperator.IsNull() || andOrOperator == "And" || andOrOperator == "AND" || andOrOperator == "&&") ? innerExpr.And(expr) : innerExpr.Or(expr);
            func = innerExpr;
        }
        catch { }
        return func;
    }

    private static MemberExpression NestedExprProp(Expression expr, string propName)
    {
        string[] arrProp = propName.Split('.');
        int arrPropCount = arrProp.Length;
        return (arrPropCount > 1) ? Expression.Property(NestedExprProp(expr, arrProp.Take(arrPropCount - 1).Aggregate((a, i) => a + "." + i)), arrProp[arrPropCount - 1]) : Expression.Property(expr, propName);
    }

    private static Expression ToExprConstant(Type prop, string value)
    {
        if (value.IsNull())
            return Expression.Constant(value);
        object val = null;
        switch (prop.FullName)
        {
            case "System.Guid":
                val = value.ToGuid();
                break;
            default:
                val = Convert.ChangeType(value, Type.GetType(prop.FullName));
                break;
        }
        return Expression.Constant(val);
    }

    private static Expression ApplyFilter(string opr, Expression left, Expression right)
    {
        Expression InnerLambda = null;
        switch (opr)
        {
            case "==":
            case "=":
                InnerLambda = Expression.Equal(left, right);
                break;
            case "<":
                InnerLambda = Expression.LessThan(left, right);
                break;
            case ">":
                InnerLambda = Expression.GreaterThan(left, right);
                break;
            case ">=":
                InnerLambda = Expression.GreaterThanOrEqual(left, right);
                break;
            case "<=":
                InnerLambda = Expression.LessThanOrEqual(left, right);
                break;
            case "!=":
                InnerLambda = Expression.NotEqual(left, right);
                break;
            case "&&":
                InnerLambda = Expression.And(left, right);
                break;
            case "||":
                InnerLambda = Expression.Or(left, right);
                break;
            case "LIKE":
                InnerLambda = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), right);
                break;
            case "NOTLIKE":
                InnerLambda = Expression.Not(Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), right));
                break;
        }
        return InnerLambda;
    }

    public static Expression<Func<T, object>> PropExpr<T>(string PropName)
    {
        ParameterExpression paramExpr = Expression.Parameter(typeof(T));
        var tempExpr = Extentions.NestedExprProp(paramExpr, PropName);
        return Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Lambda(tempExpr, paramExpr).Body, typeof(object)), paramExpr);

    }
    public static IQueryOver<T, T> OrderBy<T>(this IQueryOver<T, T> Collection, string sidx, string sord)
    {
        return sord == "asc" ? Collection.OrderBy(NHibernate.Criterion.Projections.Property(sidx)).Asc : Collection.OrderBy(NHibernate.Criterion.Projections.Property(sidx)).Desc;
    }

    public static Expression<Func<T, TResult>> And<T, TResult>(this Expression<Func<T, TResult>> expr1, Expression<Func<T, TResult>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, TResult>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    }

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
    }