jqGrid LINQ和匿名类型

jqGrid采用以下JSON格式:

{ "total": "5", "page": "2", "records": "55", "rows" : [ {"id" :"21", "cell" :["cell11", "cell12", "cell13"]}, {"id" :"22", "cell" :["cell21", "cell22", "cell23"]}, ... {"id" :"30", "cell" :["cell31", "cell32", "cell33"]}, ] } 

我正在尝试使一个方法尽可能重用,以便通过AJAX将数据传回jqGrid。

 var result = new { total = (int) Math.Ceiling((double) totalCount/PageSize), page = PageIndex, records = totalCount, rows = data.Select((d, id) => new {id, cell = d.SerializeGridParameters()}).ToArray() }; 

正如您所看到的,目前我设法添加索引而不需要额外的努力,但我遇到了现场数据的问题。

到目前为止,我设法通过使用接口来处理它:

 public interface IGridParameterListable { List SerializeGridParameters(); } 

对于我的数据(这是一个IEnumerable where T : IGridParameterListable )。
事情是我宁愿有一个generics方法,只是盲目地将对象属性值转换为List ..

听起来不太可爱,我知道,我对其他想法持开放态度。
我想尽可能避免在客户端和服务器端重复网格的数据结构。

这不是答案,只是一些源代码

如果有人想要我的ASP.NET WebForms的jqGrid实现,鉴于它很难实现,我将在这里发布代码。

首先,一些JSON类:

 public class GridFilter { public string groupOp { get; set; } public GridRule[] rules { get; set; } } public class GridRule { public string field { get; set; } public string op { get; set; } public string data { get; set; } } public class GridSettings { public bool IsSearch { get; set; } public int PageSize { get; set; } public int PageIndex { get; set; } public string SortColumn { get; set; } public string SortOrder { get; set; } public GridFilter Where { get; set; } } 

前端代码,我更改了一些,所以它允许我只用一个参数发布到服务,填充网格信息。 另外,我真的不关心单个filter,所以我只支持多重过滤模式(在我看来,这绝对是更好的)。

 

现在,对于实际的实现......首先,我们需要一些LINQ扩展方法,用于数据的排序和排序。 这些如下:

 public static IQueryable OrderBy(this IQueryable query, string sortColumn, string direction) { if (string.IsNullOrEmpty(sortColumn)) return query; string methodName = string.Format("OrderBy{0}", direction.ToLower() == "asc" ? "" : "descending"); ParameterExpression parameter = Expression.Parameter(query.ElementType, "p"); MemberExpression memberAccess = null; foreach (var property in sortColumn.Split('.')) memberAccess = MemberExpression.Property(memberAccess ?? (parameter as Expression), property); LambdaExpression orderByLambda = Expression.Lambda(memberAccess, parameter); MethodCallExpression result = Expression.Call( typeof(Queryable), methodName, new[] { query.ElementType, memberAccess.Type }, query.Expression, Expression.Quote(orderByLambda)); return query.Provider.CreateQuery(result); } public static IQueryable Where(this IQueryable query, string column, object value, string operation) { if (string.IsNullOrEmpty(column)) return query; ParameterExpression parameter = Expression.Parameter(query.ElementType, "p"); MemberExpression memberAccess = null; foreach (var property in column.Split('.')) memberAccess = MemberExpression.Property (memberAccess ?? (parameter as Expression), property); //change param value type //necessary to getting bool from string ConstantExpression filter = Expression.Constant ( Convert.ChangeType(value, memberAccess.Type) ); //switch operation LambdaExpression lambda = null; switch (operation) { case "eq": // equal { lambda = Expression.Lambda(Expression.Equal(memberAccess, filter), parameter); break; } case "ne": // not equal { lambda = Expression.Lambda(Expression.NotEqual(memberAccess, filter), parameter); break; } case "cn": // contains { Expression condition = Expression.Call(memberAccess, typeof (string).GetMethod("Contains"), Expression.Constant(value.ToString())); lambda = Expression.Lambda(condition, parameter); break; } } var result = Expression.Call( typeof(Queryable), "Where", new[] { query.ElementType }, query.Expression, lambda); return query.Provider.CreateQuery(result); } 

搜索的实际实现,作为优先选择,我将它作为成员方法放在我的GridSettings类中,但它也可以是IQueryable的扩展方法。

 public string SerializeQuery(IQueryable query, Func> select) { //filtering if (IsSearch && Where.rules != null) { if (Where.groupOp == "AND") // TODO: INSENSITIVE EQUALS, Y un enum GridGroupOperation.And.Name() { foreach (var rule in Where.rules) query = query.Where(rule.field, rule.data, rule.op); } else if (Where.groupOp == "OR") // TODO: INSENSITIVE EQUALS, Y un enum GridGroupOperation.Or.Name() { var temp = (new List()).AsQueryable(); foreach (var rule in Where.rules) { var t = query.Where(rule.field, rule.data, rule.op); temp = temp.Concat(t); } //remove repeat records query = temp.Distinct(); } } //sorting query = query.OrderBy(SortColumn, SortOrder); //count var totalCount = query.Count(); //paging var data = query.Skip((PageIndex - 1) * PageSize).Take(PageSize); //convert to grid format var result = new { total = (int)Math.Ceiling((double)totalCount / PageSize), page = PageIndex, records = totalCount, rows = data.Select((d, id) => new { id, cell = select(d) }).ToArray() }; return JsonConvert.SerializeObject(result); } 

然后,对于实际服务,我们将需要这样的片段:

 [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ToolboxItem(false)] [ScriptService] public class GridTestService : System.Web.Services.WebService { [WebMethod] [ScriptMethod] public string GetData(GridSettings grid) { var query = new FakeComputersRepository().Computers(); var response = grid.SerializeQuery(query, d => new List { d.ID.ToString(), d.IsOnline.ToString(), d.Name, d.IP, d.User }); return response; } } 

正如您所看到的,我只是获取数据,选择我想要显示的列(必须与客户端的网格中的列相同和顺序),这就是它。 我们的想法是尽可能地重复使用。

Nico,这是我用过asp.net webforms的jqgrid的最佳实现。 通过向SerializeQuery方法添加第三个参数,我做了一个小但重要的改进:实际行id的列表,以便我们可以将这些添加到结果中。 没有该列表,发送到客户端的行ID实际上只是列表中包含行数据的项的索引,而不是数据库行中的实际ID。 在您需要在jqgrid中启用编辑和删除的情况下,这是不可用的。

 public string SerializeQuery(IQueryable query, Func> select, Func> ids) { //filtering if (IsSearch && Where.rules != null) { if (Where.groupOp == "AND") // TODO: INSENSITIVE EQUALS, Y un enum GridGroupOperation.And.Name() { foreach (var rule in Where.rules) query = query.Where(rule.field, rule.data, rule.op); } else if (Where.groupOp == "OR") // TODO: INSENSITIVE EQUALS, Y un enum GridGroupOperation.Or.Name() { var temp = (new List()).AsQueryable(); foreach (var rule in Where.rules) { var t = query.Where(rule.field, rule.data, rule.op); temp = temp.Concat(t); } //remove repeat records query = temp.Distinct(); } } //sorting query = query.OrderBy(SortColumn, SortOrder); //count var totalCount = query.Count(); //paging var data = query.Skip((PageIndex - 1) * PageSize).Take(PageSize); //convert to grid format var result = new { total = (int)Math.Ceiling((double)totalCount / PageSize), page = PageIndex, records = totalCount, rows = data.Select((d) => new { id = ids(d), cell = select(d) }).ToArray() }; return JsonConvert.SerializeObject(result); } 

这可能是更好的选择。

 public string SerializeQuery(IQueryable query, Func> select) { // stuff ... var result = new { total = (int)Math.Ceiling((double)totalCount / PageSize), page = PageIndex, records = totalCount, rows = data.Select((d, id) => new { id, cell = select(d) }).ToArray() }; // stuff ... } 

我消除了对接口的需求,并将转换移动到每个特定网格的查询实现。 在这个例子中:

 [WebMethod] [ScriptMethod] public string GetData(GridSettings grid) { var query = new FakeComputersRepository().Computers(); var response = grid.SerializeQuery(query, d => new List { d.ID.ToString(), d.IsOnline.ToString(), d.Name, d.IP, d.User }); return response; } 

我想,还有一点好转。 任何其他想法,进一步扩大这一点?