jqgrid с asp.net webmethod и json работают с сортировкой, поиском по страницам, поиском и LINQ - но нужны динамические операторы - PullRequest
30 голосов
/ 10 марта 2010

ЭТО РАБОТАЕТ! .. но все еще нужна еще одна вещь ...

Хорошо, так что это и комментарий, и вопрос. Во-первых, это рабочий пример, который может помочь другим в поиске подхода asp.net webmethod / jqGrid. Приведенный ниже код полностью работает для отправки / получения параметров JSON из и в jqGrid для правильной подкачки, сортировки, фильтрации (только с одним поиском) с использованием LINQ .. он использует фрагменты здесь и там ...

Во-вторых, мой вопрос: Кто-нибудь определил подходящий метод для учета динамических операторов, отправляемых в кодовый блок? Поскольку клиент потенциально может отправлять "eq" (равно), "cn" (содержит) "gt" (больше чем), Мне нужен лучший способ динамического генерирования предложения where, которое не ограничивается только созданием строки whereclause с помощью «=» или «<>», а скорее может включать его вместе со способностью Dynamic Linq использовать .Contains или .EndsWith, и т.д.

Мне может понадобиться какая-то функция построения предикатов ..

код, который обрабатывает это на данный момент (который работает, но ограничен):

if (isSearch) {
    searchOper = getOperator(searchOper); // need to associate correct operator to value sent from jqGrid
    string whereClause = String.Format("{0} {1} {2}", searchField, searchOper, "@" + searchField);

    //--- associate value to field parameter
    Dictionary<string, object> param = new Dictionary<string, object>();
    param.Add("@" + searchField, searchString);

    query = query.Where(whereClause, new object[1] { param });
}

Продолжение шоу .........

=============================================== ===

Во-первых, JAVASCRIPT

<script type="text/javascript">
$(document).ready(function() {

    var grid = $("#grid");

    $("#grid").jqGrid({
        // setup custom parameter names to pass to server
        prmNames: { 
            search: "isSearch", 
            nd: null, 
            rows: "numRows", 
            page: "page", 
            sort: "sortField", 
            order: "sortOrder"
        },
        // add by default to avoid webmethod parameter conflicts
        postData: { searchString: '', searchField: '', searchOper: '' },
        // setup ajax call to webmethod
        datatype: function(postdata) {    
            $(".loading").show(); // make sure we can see loader text
            $.ajax({
                url: 'PageName.aspx/getGridData',  
                type: "POST",  
                contentType: "application/json; charset=utf-8",  
                data: JSON.stringify(postdata),
                dataType: "json",
                success: function(data, st) {
                    if (st == "success") {
                        var grid = $("#grid")[0];
                        grid.addJSONData(JSON.parse(data.d));
                    }
                },
                error: function() {
                    alert("Error with AJAX callback");
                }
            }); 
        },
        // this is what jqGrid is looking for in json callback
        jsonReader: {  
            root: "rows",
            page: "page",
            total: "totalpages",
            records: "totalrecords",
            cell: "cell",
            id: "id", //index of the column with the PK in it 
            userdata: "userdata",
            repeatitems: true
        },
        colNames: ['Id', 'First Name', 'Last Name'],   
        colModel: [
            { name: 'id', index: 'id', width: 55, search: false },
            { name: 'fname', index: 'fname', width: 200, searchoptions: { sopt: ['eq', 'ne', 'cn']} },
            { name: 'lname', index: 'lname', width: 200, searchoptions: { sopt: ['eq', 'ne', 'cn']} }
        ],  
        rowNum: 10,  
        rowList: [10, 20, 30],
        pager: jQuery("#pager"),
        sortname: "fname",   
        sortorder: "asc",
        viewrecords: true,
        caption: "Grid Title Here",
    gridComplete: function() {
        $(".loading").hide();
    }
    }).jqGrid('navGrid', '#pager', { edit: false, add: false, del: false },
    {}, // default settings for edit
    {}, // add
    {}, // delete
    { closeOnEscape: true, closeAfterSearch: true}, //search
    {}
)
});
</script>

=============================================== ===

Во-вторых, веб-метод C #

[WebMethod]
public static string getGridData(int? numRows, int? page, string sortField, string sortOrder, bool isSearch, string searchField, string searchString, string searchOper) {
    string result = null;

    MyDataContext db = null;
    try {
        //--- retrieve the data
        db = new MyDataContext("my connection string path");  
        var query = from u in db.TBL_USERs
                    select new User {
                        id = u.REF_ID, 
                        lname = u.LAST_NAME, 
                        fname = u.FIRST_NAME
                    };

        //--- determine if this is a search filter
        if (isSearch) {
            searchOper = getOperator(searchOper); // need to associate correct operator to value sent from jqGrid
            string whereClause = String.Format("{0} {1} {2}", searchField, searchOper, "@" + searchField);

            //--- associate value to field parameter
            Dictionary<string, object> param = new Dictionary<string, object>();
            param.Add("@" + searchField, searchString);

            query = query.Where(whereClause, new object[1] { param });
        }

        //--- setup calculations
        int pageIndex = page ?? 1; //--- current page
        int pageSize = numRows ?? 10; //--- number of rows to show per page
        int totalRecords = query.Count(); //--- number of total items from query
        int totalPages = (int)Math.Ceiling((decimal)totalRecords / (decimal)pageSize); //--- number of pages

        //--- filter dataset for paging and sorting
        IQueryable<User> orderedRecords = query.OrderBy(sortfield);
        IEnumerable<User> sortedRecords = orderedRecords.ToList();
        if (sortorder == "desc") sortedRecords= sortedRecords.Reverse();
        sortedRecords = sortedRecords
          .Skip((pageIndex - 1) * pageSize) //--- page the data
          .Take(pageSize);

        //--- format json
        var jsonData = new {
            totalpages = totalPages, //--- number of pages
            page = pageIndex, //--- current page
            totalrecords = totalRecords, //--- total items
            rows = (
                from row in sortedRecords
                select new {
                    i = row.id,
                    cell = new string[] {
                        row.id.ToString(), row.fname, row.lname 
                    }
                }
           ).ToArray()
        };

        result = Newtonsoft.Json.JsonConvert.SerializeObject(jsonData);

    } catch (Exception ex) {
        Debug.WriteLine(ex);
    } finally {
        if (db != null) db.Dispose();
    }

    return result;
}

/* === User Object =========================== */
public class User {
    public int id { get; set; }
    public string lname { get; set; }
    public string fname { get; set; }
}

=============================================== ===

В-третьих, НЕОБХОДИМОСТЬ

  1. Для того, чтобы в LINQ были динамические предложения OrderBy, мне пришлось добавить класс в папку AppCode с именем «Dynamic.cs». Вы можете получить файл из , скачав здесь . Вы найдете файл в папке «DynamicQuery». Этот файл даст вам возможность использовать динамическое предложение ORDERBY, поскольку мы не знаем, по какому столбцу мы фильтруем, кроме как при начальной загрузке.

  2. Чтобы сериализовать JSON от C-sharp до JS, я включил библиотеку JSON.net Джеймса Ньютона-Кинга, найденную здесь: http://json.codeplex.com/releases/view/37810. После загрузки появляется " Newtonsoft.Json.Compact.dll ", который вы можете добавить в папку Bin для справки

  3. Вот блок моего ИСПОЛЬЗОВАНИЯ используя Систему; использование System.Collections; using System.Collections.Generic; использование System.Linq; использование System.Web.UI.WebControls; использование System.Web.Services; используя System.Linq.Dynamic;

  4. Для ссылок на Javascript я использую следующие сценарии в соответствующем порядке на случай, если это поможет некоторым людям: 1) jquery-1.3.2.min.js ... 2) jquery-ui-1.7. 2.custom.min.js ... 3) json.min.js ... 4) i18n / grid.locale-en.js ... 5) jquery.jqGrid.min.js

  5. Для CSS я использую потребности jqGrid, а также тему пользовательского интерфейса jQuery: 1) jquery_theme / jquery-ui-1.7.2.custom.css ... 2) ui.jqgrid.css

Ключом к получению параметров из JS в WebMethod без необходимости разбора несериализованной строки на бэкэнде или настройки некоторой логики JS для переключения методов для различного числа параметров был этот блок

postData: { searchString: '', searchField: '', searchOper: '' },

Эти параметры будут по-прежнему установлены правильно, когда вы действительно выполняете поиск, а затем сбрасываетесь на пустые, когда вы «сбрасываете» или хотите, чтобы сетка не выполняла фильтрацию

Надеюсь, это поможет некоторым другим !!!! И спасибо, если у вас есть время, чтобы прочитать и ответить о динамическом подходе к созданию выражения where с операторами во время выполнения

Ответы [ 2 ]

1 голос
/ 14 апреля 2010

Рассмотрим этот метод расширения, который преобразует строку в выражение MemberExpression:

public static class StringExtensions
{
    public static MemberExpression ToMemberExpression(this string source, ParameterExpression p)
    {
        if (p == null)
            throw new ArgumentNullException("p");

        string[] properties = source.Split('.');

        Expression expression = p;
        Type type = p.Type;

        foreach (var prop in properties)
        {
            var property = type.GetProperty(prop);
            if (property == null)
                throw new ArgumentException("Invalid expression", "source");

            expression = Expression.MakeMemberAccess(expression, property);
            type = property.PropertyType;
        }

        return (MemberExpression)expression;
    }
}

Приведенный ниже метод преобразует имеющиеся у вас строки в лямбда-выражение, которое можно использовать для фильтрации запроса Linq. Это универсальный метод с T в качестве сущности домена.

    public virtual Expression<Func<T, bool>> CreateExpression<T>(string searchField, string searchString, string searchOper)
    {
        Expression exp = null;
        var p = Expression.Parameter(typeof(T), "p");

        try
        {
            Expression propertyAccess = searchField.ToExpression(p);

            switch (searchOper)
            {
                case "bw":
                    exp = Expression.Call(propertyAccess, typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }), Expression.Constant(searchString));
                    break;
                case "cn":
                    exp = Expression.Call(propertyAccess, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(searchString));
                    break;
                case "ew":
                    exp = Expression.Call(propertyAccess, typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }), Expression.Constant(searchString));
                    break;
                case "gt":
                    exp = Expression.GreaterThan(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
                    break;
                case "ge":
                    exp = Expression.GreaterThanOrEqual(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
                    break;
                case "lt":
                    exp = Expression.LessThan(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
                    break;
                case "le":
                    exp = Expression.LessThanOrEqual(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
                    break;
                case "eq":
                    exp = Expression.Equal(propertyAccess, Expression.Constant(searchString.ToType(propertyAccess.Type), propertyAccess.Type));
                    break;
                case "ne":
                    exp = Expression.NotEqual(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
                    break;
                default:
                    return null;
            }

            return (Expression<Func<T, bool>>)Expression.Lambda(exp, p);
        }
        catch
        {
            return null;
        }
    }

Итак, вы можете использовать его так:

db.TBL_USERs.Where(CreateExpression<TBL_USER>("LAST_NAME", "Costa", "eq"));
0 голосов
/ 27 марта 2010

Дайте этой статье писк. Он ориентирован на использование jqgrid в MVC, но вы можете извлечь соответствующую информацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...