After updating to 2012.2.913, our updatable grids stopped being able to save records to the data source. ModelState.IsValid was returning false for "Id", saying "The Id field is required". The Id field is a Guid which is auto-populated by our NHibernate data model after a record is added, so we found this puzzling.
Our simplest grids were like this:
@(Html.Kendo().Grid<VMMudType>()
.Name("vMudTypeGrid")
.DataSource(datasource => datasource
.Ajax()
.Model(model => model.Id(m => m.Id))
.Create(r => r.Action("Insert", "MudTypeGrid"))
.Read(r => r.Action("Select", "MudTypeGrid"))
.Update(r => r.Action("Update", "MudTypeGrid"))
.Destroy(r => r.Action("Delete", "MudTypeGrid"))
)
.Columns(columns =>
{
columns.Bound(a => a.Name);
columns.Command(command =>
{
command.Edit();
command.Destroy();
});
})
.Editable(ed => ed.Mode(GridEditMode.InLine))
.Sortable()
.Filterable()
.ToolBar(commands => commands.Create())
)
Data model had only the two fields, "Id", which was a Guid, and "Name", which was a string.
Looking at the actual save requests for the pre-upgrade grid versus the upgraded version in Fiddler, I saw the following difference in the POST results: The old version sent "sort=&group=&filter=&Id=00000000-0000-0000-0000-000000000000&Name=Water-Based", while the new version sent "sort=&group=&filter=&Id=&Name=Water-Based". The generated Javascript for the grid also showed this difference: model:{id:"Id",fields:{Name:{type:"string"},Id:{type:"object",defaultValue:"00000000-0000-0000-0000-000000000000"}}} for the older version, vs. "model":{"id":"Id","fields":{"Name":{"type":"string"},"Id":{"type":"string"}}} for the new version.
The change that broke things seems to have been in TypeExtensions.cs, where ToJavaScriptType(this type) had a new clause for Guids:
if (type.GetNonNullableType() == typeof(Guid))
{
return "String";
}
There are workarounds for this. I changed our Insert grid controller to specifically not bind on Id:
public virtual ActionResult Insert([DataSourceRequest] DataSourceRequest request, [Bind(Exclude = "Id")] TViewModel vm)
It was also possible to work around this by changing ".Model(model => model.Id(m => m.Id))" to
.Model(model =>
{
model.Id(m => m.Id);
model.Field(m => m.Id).DefaultValue(Guid.Empty);
})
But the former will work better with our framework, because we can put it into our grid controller parent class.
I could also have made the change to TypeExtensions to take out the Guid clause, but without knowing more about the rationale for the change, I didn't think I should. What was the reason for having Javascript treat Guids like strings, and would there be a way to do this which didn't break things when adding new records with Guids that are auto-populated by the data model?
Aaron Humphrey
Pleasant Solutions
Our simplest grids were like this:
@(Html.Kendo().Grid<VMMudType>()
.Name("vMudTypeGrid")
.DataSource(datasource => datasource
.Ajax()
.Model(model => model.Id(m => m.Id))
.Create(r => r.Action("Insert", "MudTypeGrid"))
.Read(r => r.Action("Select", "MudTypeGrid"))
.Update(r => r.Action("Update", "MudTypeGrid"))
.Destroy(r => r.Action("Delete", "MudTypeGrid"))
)
.Columns(columns =>
{
columns.Bound(a => a.Name);
columns.Command(command =>
{
command.Edit();
command.Destroy();
});
})
.Editable(ed => ed.Mode(GridEditMode.InLine))
.Sortable()
.Filterable()
.ToolBar(commands => commands.Create())
)
Data model had only the two fields, "Id", which was a Guid, and "Name", which was a string.
Looking at the actual save requests for the pre-upgrade grid versus the upgraded version in Fiddler, I saw the following difference in the POST results: The old version sent "sort=&group=&filter=&Id=00000000-0000-0000-0000-000000000000&Name=Water-Based", while the new version sent "sort=&group=&filter=&Id=&Name=Water-Based". The generated Javascript for the grid also showed this difference: model:{id:"Id",fields:{Name:{type:"string"},Id:{type:"object",defaultValue:"00000000-0000-0000-0000-000000000000"}}} for the older version, vs. "model":{"id":"Id","fields":{"Name":{"type":"string"},"Id":{"type":"string"}}} for the new version.
The change that broke things seems to have been in TypeExtensions.cs, where ToJavaScriptType(this type) had a new clause for Guids:
if (type.GetNonNullableType() == typeof(Guid))
{
return "String";
}
There are workarounds for this. I changed our Insert grid controller to specifically not bind on Id:
public virtual ActionResult Insert([DataSourceRequest] DataSourceRequest request, [Bind(Exclude = "Id")] TViewModel vm)
It was also possible to work around this by changing ".Model(model => model.Id(m => m.Id))" to
.Model(model =>
{
model.Id(m => m.Id);
model.Field(m => m.Id).DefaultValue(Guid.Empty);
})
But the former will work better with our framework, because we can put it into our grid controller parent class.
I could also have made the change to TypeExtensions to take out the Guid clause, but without knowing more about the rationale for the change, I didn't think I should. What was the reason for having Javascript treat Guids like strings, and would there be a way to do this which didn't break things when adding new records with Guids that are auto-populated by the data model?
Aaron Humphrey
Pleasant Solutions