web-dev-qa-db-fra.com

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

CECI FONCTIONNE! .. mais a encore besoin d'une chose ...

D'accord, c'est donc à la fois un "commentaire" et une question. Premièrement, voici l'exemple de travail qui peut aider d'autres personnes à rechercher une approche asp.net webmethod/jqGrid. Le code ci-dessous fonctionne complètement pour envoyer/recevoir des paramètres JSON de et vers jqGrid afin d'avoir une pagination, un tri, un filtrage corrects (avec recherche unique) à l'aide de LINQ .. il utilise des morceaux d'ici et là ...

Deuxièmement, ma question est-elle la suivante: Quelqu'un a-t-il déjà déterminé une méthode appropriée pour comptabiliser les opérateurs dynamiques envoyés au code ci-dessous? Etant donné que le client peut potentiellement envoyer "eq" (égal), "cn" (contient) "gt" (supérieur à), il me faut un meilleur moyen de générer de manière dynamique une exception qui ne se limite pas à la construction d'un whereeclause chaîne avec "=" ou "<>", mais peut plutôt englober cela avec la capacité de Dynamic Linq à utiliser .Contains ou .EndsWith, etc.

J'ai peut-être besoin d'une sorte de fonction de construction de prédicats.

code qui gère cela à partir de maintenant (ce qui fonctionne, mais 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 .........

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

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>

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

Deuxièmement, C WEBMETHOD 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; }
}

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

Troisièmement, les nécessités

  1. Afin d'avoir des clauses OrderBy dynamiques dans le LINQ, je devais extraire une classe dans mon dossier AppCode appelé 'Dynamic.cs'. Vous pouvez récupérer le fichier de en le téléchargeant ici. Vous trouverez le fichier dans le dossier "DynamicQuery". Ce fichier vous permettra d'utiliser la clause ORDERBY dynamique, car nous ne savons pas dans quelle colonne nous filtrons, à l'exception du chargement initial.

  2. Pour sérialiser le JSON du C-sharp au JS, j'ai incorporé le JSON.net James Newton-King JSON.net DLL trouvé 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 votre dossier Bin comme référence

  3. Voici mon bloc USING Utilisant System; Utilisant System.Collections; Utilisant System.Collections.Generic; Utilisant System.Linq; Utilisant System.Web.UI.WebControls; À l'aide de System.Web.Services; À l'aide de System.Linq.Dynamic;

  4. Pour les références Javascript, j'utilise les scripts suivants dans leur ordre respectif au cas où cela aiderait 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, j'utilise les nécessités de jqGrid ainsi que le thème de l'interface utilisateur de jQuery: 1) jquery_theme/jquery-ui-1.7.2.custom.css ... 2) ui.jqgrid.css

La clé pour obtenir les paramètres du JS vers le WebMethod sans avoir à analyser une chaîne non sérialisée sur le serveur ou à configurer une logique JS pour changer de méthode pour un nombre différent de paramètres était ce bloc

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

Ces paramètres sont toujours définis correctement lorsque vous effectuez une recherche, puis sont réinitialisés à vides lorsque vous les réinitialisez ou si vous souhaitez que la grille ne filtre pas

J'espère que cela aide les autres !!!! Et merci si vous avez le temps de lire et de répondre concernant l’approche dynamique de la création de la localisation avec les opérateurs lors de l’exécution

30
aimlessWonderer

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

Donc, vous pouvez l'utiliser comme ceci:

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

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

0
Sky Sanders