29 votes

jqgrid avec asp.net webmethod et json travaillant avec le tri, la pagination, la recherche et LINQ - mais nécessite des opérateurs dynamiques

CELA FONCTIONNE! .. mais il y a encore une chose de plus...

Ok, donc c'est à la fois un "commentaire" et de la question. Tout d'abord, l'exemple de travail qui peuvent aider les autres dans la recherche d'un asp.net webmethod / jqGrid approche. Le code ci-dessous complètement travaille pour l'envoi/la réception de JSON paramètres à partir et à jqGrid afin d'avoir une pagination, tri, de filtrage (avec une seule recherche uniquement) en utilisant LINQ.. il utilise des morceaux à partir d'ici et de là-bas...

La deuxième, c'est de ma question: Quelqu'un a déterminé une méthode appropriée pour la comptabilisation de la dynamique des opérateurs d'être envoyé dans le codebehind? Depuis le client peut potentiellement envoyer "eq" (égal), "cn" (contient) "gt" (plus grand que), j'ai besoin d'une meilleure façon de générer dynamiquement une whereclause qui n'est pas simplement limitée à me construire une whereclause chaîne avec "=" ou "<>", mais plutôt peut comprendre que le long avec Dynamique de Linq capacité à utiliser .Contient ou .EndsWith, etc.

J'ai peut-besoin d'une sorte de prédicat générateur de fonction ..

le code qui gère cela comme de maintenant (ce qui fonctionne, mais c'est limité):

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

Avec le spectacle.........

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

Tout d'abord, LE 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>

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

La seconde, LE C# WEBMETHOD

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

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

La troisième, de première nécessité

  1. Afin de disposer d'dynamique OrderBy clauses dans le LINQ, j'ai dû tirer dans une classe à mon AppCode le dossier appelé " Dynamique.cs'. Vous pouvez récupérer le fichier de téléchargement ici. Vous trouverez ce fichier dans le "DynamicQuery" le dossier. Ce fichier vous donnera la possibilité d'utiliser dynamique clause ORDERBY puisque nous ne savons pas quelle colonne nous sommes filtrage par exception à la charge initiale.

  2. Pour sérialiser le JSON de retour de la C-sharp pour le JS, j'ai incorporé la James Newton-King JSON.net DLL disponible ici : http://json.codeplex.com/releases/view/37810. Après le téléchargement, il y a un "Newtonsoft.Json.Compact.dll" que vous pouvez ajouter dans le dossier Bin comme une référence

  3. Voici ma à l'AIDE du bloc en utilisant le Système; en utilisant le Système.Collections; en utilisant le Système.Les Collections.Générique; en utilisant le Système.Linq; en utilisant le Système.Web.L'INTERFACE utilisateur.Contrôles webcontrols; en utilisant le Système.Web.Services; en utilisant le Système.Linq.Dynamique;

  4. Pour le Javascript, des références, je suis en utilisant les scripts suivants dans l'ordre, dans le cas qui aide à certaines personnes: 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. Pour le CSS, je suis en utilisant jqGrid de produits, ainsi que le Thème jQuery UI: 1) jquery_theme/jquery-ui-1.7.2.la coutume.css ... 2) de l'interface utilisateur.jqgrid.css

La clé pour obtenir les paramètres de la JS à la WebMethod sans avoir à analyser un délinéarisé chaîne sur le backend, ou avoir pour l'installation de certains JS logique pour passer méthodes pour différents nombres de paramètres a été ce bloc

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

Ces paramètres seront toujours réglé correctement lorsque vous faites une recherche, et alors remis à vide lorsque vous "reset" ou voulez la grille de ne pas faire de filtrage

Espérons que cela aide certains autres!!!! Et merci si vous avez le temps de lire et de répondre au sujet de l'approche dynamique de la construction de la whereclause avec les opérateurs au moment de l'exécution

1voto

Jonathas Costa Points 426

Considérez cette méthode d'extension, qui convertit une chaîne en une 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;
    }
}
 

La méthode ci-dessous convertit les chaînes que vous avez en une expression Lambda, que vous pouvez utiliser pour filtrer une requête Linq. Il s'agit d'une méthode générique, avec T comme entité de domaine.

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

Vous pouvez donc l'utiliser comme ceci:

 db.TBL_USERs.Where(CreateExpression<TBL_USER>("LAST_NAME", "Costa", "eq"));
 

0voto

Sky Sanders Points 19557

Donnez un coup d'œil à cet article . Il se concentre sur l'utilisation de jqgrid dans MVC mais vous pouvez extraire les informations pertinentes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X