Kendo UI 网格插入/更新创建重复记录(再次)
Posted
技术标签:
【中文标题】Kendo UI 网格插入/更新创建重复记录(再次)【英文标题】:Kendo UI Grid Inserts/Updates create Duplicate Records (again) 【发布时间】:2013-04-28 17:22:43 【问题描述】:我和丹尼尔在这个话题中遇到了同样的问题,但他的解决方案对我不起作用:
http://www.kendoui.com/forums/ui/grid/kendo-ui-grid-inserts-updates-create-duplicate-records.aspx#-jhxqRrNAUGsTFJaC-Ojwg
所以用例。用户依次添加2条新记录:
-
按网格的“添加新记录”按钮
填写字段(name="Alex",amount=10,comment="first")。
记录一已准备就绪。按“保存”。 (数据进入控制器而不是数据库)
用户在网格中看到一条记录
再次按“添加新记录”按钮
填写字段(name="Bob",amount=20,comment = "second")。记录一已准备就绪。按“保存”。数据进入控制器而不是数据库。 在这一刻发生了一些事情,网格再次发送 Ajax 请求并记录一个数据到控制器。
用户更新网格并查看三个记录
“Alex | 10 | first”(重复记录)ID = 1
“鲍勃 | 20 | 秒” ID = 2
“亚历克斯 | 10 | 第一个” ID = 1
他们建议返回一个 ID 以使用新记录正确绑定\更新数据源。 然后我返回它(来自数据库的新 ID 以 bouns 实体作为响应)!这没有帮助。 仅当我使用 F5 添加第一条记录并刷新页面,然后添加第二条记录时,一切正常。但是如果再添加一条,第三条记录-问题又出现了
控制器中的代码:
[HttpPost]
public JsonResult Create(BonusDto bonusDto)
BonusAggregate bonus;
if (bonusDto.Amount <= 0)
throw new ArgumentOutOfRangeException("Amount should be more than 0");
if (bonusDto.EmployeeId <= 0)
throw new ArgumentNullException("You should specify an existing employee");
using (var dbContext = new DatabaseContext())
BonusesRepository = new BonusesRepository(dbContext);
var employeeRepository = new EmployeesRepository(dbContext);
bonus = new BonusFactory(employeeRepository).Create(bonusDto);
BonusesRepository.Save(bonus);
HttpContext.Response.StatusCode = (int)HttpStatusCode.Created;
return Json(bonus); // try to return ID after bonus was saved
界面代码
// creates bonuses grid control
$("#bonusesGrid").kendoGrid(
dataSource: bonusesDataSource,
toolbar: ["create"],
editable: "inline",
columns: [
"BonusId",
"EmployeeId",
field: "EmployeeLastName",
editor: employeeAutocompletingEditor,
template: "#=EmployeeLastName#"
,
"Amount",
field: "Comment",
titel: "Comment",
editor: textareaEditor,
filterable:
operators:
number:
contains: "Contains"
,
command: ["edit"],
title: " "
],
save: function(e)
if (newValueEmployeeId !== undefined &&
newValueEmployeeLastName !== undefined &&
newValueEmployeeLastName !== "")
setNewValueEmployeeIdAndLastName(newValueEmployeeId, newValueEmployeeLastName);
gridDataSource.model.EmployeeId = newValueEmployeeId; // it's a hack to bind model and autocomplete control
gridDataSource.model.EmployeeLastName = newValueEmployeeLastName;
else
gridDataSource.model.EmployeeId = currentValueEmployeeId;
gridDataSource.model.EmployeeLastName = currentValueEmployeeLastName;
,
edit: function(e)
setCurrentValueEmployeeIdAndLastName(e.model.EmployeeId, e.model.EmployeeLastName);
,
cancel: function(e)
setCurrentValueEmployeeIdAndLastName(e.model.EmployeeId, e.model.EmployeeLastName);
);
奖金数据来源:
// bind json result from /Bonuses/GetPagedJsonBonuses
var bonusesDataSource = new kendo.data.DataSource(
transport:
read:
url: "@Url.Action("GetPagedJsonBonuses", "Bonuses")",
type : "GET",
contentType: "application/json",
dataType: "json",
cache: false
,
create:
url: "@Url.Action("Create", "Bonuses")",
dataType: "json",
type: "POST"
,
parameterMap: function(options, operation)
if (operation === "update" || operation === "create")
// correct format for conversion
var d = new Date(options.Date);
options.Date = kendo.toString(d, dateFormat);
// updates the BonusDTO.EmployeeId with selected value
if (newValueEmployeeId !== undefined)
options.EmployeeId = newValueEmployeeId;
if(operation === "read")
options.filter = setFormattedFilterDate(options.filter);
return options;
,
pageSize: 15,
serverPaging: true,
serverSorting: true,
serverFiltering: true,
error: showErrorMessage,
schema:
data: "Data", // PagedResponse.Data
total: "TotalCount", // PagedResponse.TotalCount
model:
id: "BonusId", // Data
fields:
EmployeeId: type: "number" ,
EmployeeLastName:
type: "string",
editable: true,
nulable: false,
validation: required: message: "Employee's last name is required"
,
Date:
type: "date",
editable: true,
nullable: false,
validation:
required: message: "Date is required to be set"
,
Amount:
type: "number",
editable: true,
nullable: false,
defaultValue: 1,
validation:
required: message: "Amount is required to be set"
,
Comment: type: "string", editable: true
// fields
// model
// schema
);
【问题讨论】:
【参考方案1】:我没有在我的代码中看到这个问题。但是,我在刷新网格的创建和更新事件上确实有一个“完整”事件处理程序 - 它可能会对您有所帮助:
dataSource:
type: "jsonp",
transport:
read: UrlBase + "getAll",
update:
url: UrlBase + "Update",
dataType: "jsonp",
complete: function (e)
$("#grid").data("kendoGrid").dataSource.read();
,
create:
url: UrlBase + "create",
dataType: "jsonp",
complete: function (e)
$("#grid").data("kendoGrid").dataSource.read();
,
destroy:
url: UrlBase + "destroy",
dataType: "jsonp",
complete: function (e)
$("#grid").data("kendoGrid").dataSource.read();
,
...
【讨论】:
谢谢,我试试。 '#grid' 是网格的元素名称吗?什么是数据中的 kendoGrid("kendoGrid") ??? 是网格的元素id。<div id="grid" style="width: 960px">
。 kendoGrid 等是内部 KendoGrid 值,因此它们将为您工作。
再次感谢。有用。但是我浏览了文档并没有发现有关事件“完成”的信息。你是怎么找到的?
我没有回去看也找不到!它必须要么在较旧的文档中,要么在某处的 SO 答案中。我能找到的最接近的信息是在剑道论坛上——但不是相同的事件。 kendoui.com/forums/framework/data-source/…【参考方案2】:
是的,hamed 是正确的。您的“创建”操作结果从您的模型传入要保存到数据库的对象。让数据访问层中的 INSERT 返回数据库中新创建的键(“ID”)。使用此键现在设置模型上的“ID”字段,该字段已传递到操作结果,然后作为 JSON 传递回视图。现在网格应该知道它刚刚创建了这个记录,不需要对它做更多的事情。否则,模型对象返回时“ID”字段设置为 0,因此网格认为它仍然需要添加此记录。
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Grid_Create([DataSourceRequest] DataSourceRequest request, MyObject obj)
if (obj != null && ModelState.IsValid)
obj.Id = _myService.Create(obj);
return Json(new[] obj .ToDataSourceResult(request, ModelState));
【讨论】:
这个答案更好。您不需要因为插入而再次读取网格 - 它会在 UI 中处理。 是的,您需要确保 id 已设置且名称与架构中定义的相同。有关详细信息,请参阅此链接中的重要说明。 docs.telerik.com/kendo-ui/api/javascript/data/…【参考方案3】:当您在读取操作中未将主键传递给查看时会发生此错误。
问候
【讨论】:
【参考方案4】:Quinton Bernhardt 的完整事件的替代方法:将 dataSource.read() 绑定到 kendo 同步事件。
我正在使用不公开同步事件的 kendo 的 C# MVC 的 html 助手,因此我必须在设置网格后对其进行修改。
在窗口加载时:
var grid = $("#GridName").data("kendoGrid");
grid.dataSource.bind("sync", function ()
$("#GridName").data("kendoGrid").dataSource.read();
);
保存请求完成后触发同步事件。 dataSource.read()
从服务器获取最新信息,包括在服务器端设置的 id。
【讨论】:
这仅适用于我的非分层网格。当用户多次添加时,分层网格仍然重复插入。【参考方案5】:我遇到了类似的问题,进行了各种试验,但通过以下试验解决了
jQuery
create:
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
url: "../../ajax/ajaxGv.aspx/addstaff"
,
parameterMap: function (options, operation)
if (operation == "create" && options.models)
return JSON.stringify( "oStaff": options.models );
VB.Net
'Adding Staff
<System.Web.Services.WebMethod()> _
Public Shared Sub addStaff(ByVal oStaff As Object)
Dim strJson As String = JsonConvert.SerializeObject(oStaff)
Dim lstStaff As List(Of Staff) = JsonConvert.DeserializeObject(Of List(Of Staff))(strJson)
Dim db As New LiveB2cDataContext
Try
db.Staff.InsertAllOnSubmit(lstStaff)
Next
db.SubmitChanges()
'Fix is that you need to return the objects you have added in the database back as json to kendo
strJson = JsonConvert.SerializeObject(lstStaff, Formatting.None)
WriteJson(strJson) ' Returning the objects added as json back to Kendo
Catch ex As Exception
ErrorLog(ex)
End Try
End Sub
Public Shared Sub WriteJson(strJson As String)
Try
HttpContext.Current.Response.Write(strJson)
HttpContext.Current.Response.Flush()
HttpContext.Current.ApplicationInstance.CompleteRequest()
HttpContext.Current.Response.SuppressContent = True
Catch ex As Exception
ErrorLog(ex)
End Try
End Sub
Fix is that you need to return the objects you have added in the database back as json to kendo
【讨论】:
【参考方案6】:我不确定这是否是您的问题的一部分,但在您的 DataSource 架构模型中,您指定 ID 是名为“BonusId”的字段,但该字段未在字段数组中指定。
【讨论】:
你的意思是这部分代码:schema: model: id: "BonusId", // THIS ONE?字段: EmployeeId: ...,EmployeeLastName:... ....如果是这样,那是正确的。 ID 不是字段列表的一部分。 ID 必须直接在“模型”区域中指定。【参考方案7】:我遇到了一个类似的问题。
我修复了它,但确保模型中的 id 是指一个字段:-
model:
id: "Id",
fields:
Id: editable: false, type: "number" ,
AnotherName: editable: true, type: "string" ,
AnotherId: editable: true, type: "number"
【讨论】:
【参考方案8】:这可能无法解决提问者的问题,但希望可以帮助遇到同样问题的人。
对我们来说,这个问题是由 JSON 中返回的错误引起的。一些必需的属性没有值,但与我们在网格中显示的数据无关。在网格中给这些属性一个默认值解决了这个问题。
您可以使用Fiddler Web Debugging Tools 查看返回的 JSON。
【讨论】:
以上是关于Kendo UI 网格插入/更新创建重复记录(再次)的主要内容,如果未能解决你的问题,请参考以下文章
启用服务器过滤、排序、分页会中断 MVC Kendo UI 网格的 SignalR 客户端更新