Telerik MVC Grid动态模型批量编辑无法获取更新记录
解决Telerik MVC Grid批量编辑时动态模型无法获取Id的问题
问题根源
- 批量提交参数名称不匹配:Telerik Grid批量更新默认将修改后的数据以
models为参数名提交,你的Update方法用了data作为参数名,导致模型绑定异常。 - 动态类型模型绑定限制:
dynamic+ExpandoObject的组合在MVC批量模型绑定时,无法正确映射Id等属性,JSON反序列化器无法将提交的数据正确转换为ExpandoObject集合。
修复方案
方案1:用JArray解析提交数据(推荐)
直接使用JArray接收提交的JSON数据,手动提取属性,避开动态类型绑定的坑:
using Newtonsoft.Json.Linq; // 需要引用Newtonsoft.Json包 public JsonResult gridUpdate([DataSourceRequest] DataSourceRequest request, JArray models) { foreach (JObject row in models) { // 直接提取Id,注意类型和定义一致(你的Id是int类型) int id = row.Value<int>("Id"); // 获取产品列的更新值 string productA = row.Value<string>("ProductA"); string productB = row.Value<string>("ProductB"); string productC = row.Value<string>("ProductC"); // 这里写你的更新逻辑 // UpdateRecord(id, productA, productB, productC); } return Json(models.ToDataSourceResult(request)); }
方案2:使用强类型ViewModel+动态属性
如果需要保留动态列的灵活性,可以创建基础ViewModel,用字典存储动态产品属性:
1. 定义ViewModel
public class GridRowViewModel { public int Id { get; set; } public string LastName { get; set; } public string FirstName { get; set; } public Dictionary<string, object> Products { get; set; } = new Dictionary<string, object>(); }
2. 修改Read方法构造数据
public JsonResult gridRead([DataSourceRequest] DataSourceRequest request) { try { List<GridRowViewModel> list = new List<GridRowViewModel>(); for(int i = 0; i <= 50; i++) { var row = new GridRowViewModel { Id = i, LastName = "Last Name " + i.ToString(), FirstName = "First Name " + i.ToString() }; // 添加动态产品属性 row.Products["ProductA"] = "Product A" + i.ToString(); row.Products["ProductB"] = "Product B" + i.ToString(); row.Products["ProductC"] = "Product C" + i.ToString(); list.Add(row); } return Json(list.ToDataSourceResult(request)); } catch (Exception ex) { return Json(new DataSourceResult() { Errors = new { Message = "Error: " + ex.Message, ExceptionMessage = ex.Message } }); } }
3. 更新Grid视图配置
@(Html.Kendo().Grid<GridRowViewModel>() .Name("myGrid") .ToolBar(toolbar => toolbar.Save()) .Columns(column => { column.Bound(m => m.Id).Hidden(true); column.Bound(m => m.LastName); column.Bound(m => m.FirstName); // 动态绑定产品列 column.Bound(m => m.Products["ProductA"]).Title("ProductA"); column.Bound(m => m.Products["ProductB"]).Title("ProductB"); column.Bound(m => m.Products["ProductC"]).Title("ProductC"); }) .Editable(editable => editable.Mode(GridEditMode.InCell)) .AutoBind(true) .DataSource(dataSource => dataSource .Ajax() .Batch(true) .Model(model => { model.Id(m => m.Id); model.Field(m => m.Id).Editable(false); model.Field(m => m.LastName).Editable(false); model.Field(m => m.FirstName).Editable(false); // 配置动态产品字段可编辑 model.Field(m => m.Products["ProductA"]).Editable(true); model.Field(m => m.Products["ProductB"]).Editable(true); model.Field(m => m.Products["ProductC"]).Editable(true); }) .Read(read => read.Action("gridRead", "myController")) .Update(update => update.Action("gridUpdate", "myController")) ) )
4. Update方法接收强类型数据
public JsonResult gridUpdate([DataSourceRequest] DataSourceRequest request, IEnumerable<GridRowViewModel> models) { foreach(var model in models) { int id = model.Id; // 正常获取Id string productA = model.Products["ProductA"].ToString(); // 执行更新逻辑 } return Json(models.ToDataSourceResult(request)); }
额外注意事项
- 确保Grid Model中Id字段的类型和实际数据一致(你的代码里Id是int,但之前用string接收,这会导致类型转换问题)。
- 隐藏列的Id必须在Grid Model中标记为
Id,否则Telerik无法识别行的唯一标识,提交时不会包含Id。
内容的提问来源于stack exchange,提问作者user3035024
相关产品推荐
相关产品推荐

