This question is locked. New answers and comments are not allowed.
I have implemented a server bound grid using Entity Framework to edit/update/delete with paging, sorting, filtering. I attached project and database.
The issue is when I sort on the PROCESS_OBJECT_TYPE column I get this error:
{"DbSortClause expressions must have a type that is order comparable.Parameter name: key"}
When I filter on the PROCESS_OBJECT_TYPE column, the filter operator list is empty and you get this error;
"Object reference not set to an instance of an object."
This column is a type property of the PROCESS_OBJECT which is the model of the view and is not a simple scalar. It uses a display and edit template view for adding/updating new records in the grid with a drop down.
How can I enable sorting or filtering for this column?
View:
Controller:
Thanks
The issue is when I sort on the PROCESS_OBJECT_TYPE column I get this error:
{"DbSortClause expressions must have a type that is order comparable.Parameter name: key"}
When I filter on the PROCESS_OBJECT_TYPE column, the filter operator list is empty and you get this error;
"Object reference not set to an instance of an object."
This column is a type property of the PROCESS_OBJECT which is the model of the view and is not a simple scalar. It uses a display and edit template view for adding/updating new records in the grid with a drop down.
How can I enable sorting or filtering for this column?
View:
@model IEnumerable<TelerikMvcApplication2.PROCESS_OBJECT> @{ ViewData["Title"] = "Editing Jobs"; } <h2>@ViewData["Title"]</h2> <p> </p> @{Html.Telerik().Grid<TelerikMvcApplication2.PROCESS_OBJECT>(Model) .Name("Jobs") .ToolBar(commands => commands.Insert()) .DataKeys(keys => { keys.Add(c => c.OBJECT_ID); }) .DataBinding(dataBinding => dataBinding .Server() .Select("EditingServerSide", "Job", new { mode = mode, type = type, pageInput = ViewData["pageInput"], nextPrevious = ViewData["nextPrevious"], numeric = ViewData["numeric"], position = position, currentPage = currentPage, pageSize = ViewData["pageSize"] }) .Insert("Insert", "Job", new { mode = mode, type = type, pageInput = ViewData["pageInput"], nextPrevious = ViewData["nextPrevious"], numeric = ViewData["numeric"], position = position, currentPage = currentPage, pageSize = ViewData["pageSize"] }) .Update("Save", "Job", new { mode = mode, type = type, pageInput = ViewData["pageInput"], nextPrevious = ViewData["nextPrevious"], numeric = ViewData["numeric"], position = position, currentPage = currentPage, pageSize = ViewData["pageSize"] }) .Delete("Delete", "Job", new { mode = mode, type = type, pageInput = ViewData["pageInput"], nextPrevious = ViewData["nextPrevious"], numeric = ViewData["numeric"], position = position, currentPage = currentPage, pageSize = ViewData["pageSize"] })) .Columns(columns => { columns.Bound(o => o.OBJECT_ID).Title("Object ID").ReadOnly(true); columns.Bound(o => o.PROCESS_OBJECT_TYPE).Title("Object Type"); //.Sortable(false).Filterable(false); columns.Bound(o => o.OBJECT_NAME).Title("Name"); columns.Command(commands => { commands.Edit(); commands.Delete(); }).Width(200).Title("Action"); }) .Pageable(paging => paging.Style(pagerStyles).Position(position).PageTo(currentPage)) .Editable(editing => editing.Mode(mode)) .Sortable().Filterable().Render(); } Controller:
{ public class JobController : Controller { private BODS_ETL_CONTROLEntities db = new BODS_ETL_CONTROLEntities(); public void setViewData(GridEditMode? mode, GridButtonType? type, bool? pageInput, bool? nextPrevious, bool? numeric, GridPagerPosition? position, int? currentPage, bool? pageSize) { ViewData["pageInput"] = pageInput ?? false; ViewData["nextPrevious"] = nextPrevious ?? true; ViewData["numeric"] = numeric ?? true; ViewData["pageSize"] = pageSize ?? false; ViewData["position"] = position ?? GridPagerPosition.Bottom; ViewData["currentPage"] = currentPage ?? 1; ViewData["mode"] = mode ?? GridEditMode.InLine; ViewData["type"] = type ?? GridButtonType.Text; } public ActionResult EditingServerSide(GridEditMode? mode, GridButtonType? type, bool? pageInput, bool? nextPrevious, bool? numeric, GridPagerPosition? position, int? currentPage, bool? pageSize) { setViewData(mode,type,pageInput,nextPrevious,numeric,position,currentPage,pageSize); //Jobs Only var process_object = db.PROCESS_OBJECT.Include("PROCESS_OBJECT_TYPE").Include("PROCESS_OBJECT_TYPE"); //.Where(o => o.OBJECT_TYPE_ID == 1); //return View(new GridModel(process_object.ToList())); PopulateJobTypes(); return View(process_object); } [AcceptVerbs(HttpVerbs.Post)] public ActionResult Insert(GridEditMode mode, GridButtonType type, bool? pageInput, bool? nextPrevious, bool? numeric, GridPagerPosition? position, int? currentPage, bool? pageSize) { setViewData(mode, type, pageInput, nextPrevious, numeric, position, currentPage, pageSize); PROCESS_OBJECT process_object = new PROCESS_OBJECT(); //Query the max ID of the obejcts to set the object id. //Perform model binding (fill the product properties and validate it). if (TryUpdateModel(process_object)) { Int32 id = db.PROCESS_OBJECT.Max(u => u.OBJECT_ID) + 1; process_object.OBJECT_ID = id; //Need to attach an existing PROCESS_OBJECT_TYPE entity from the database to this new PROCESS_OBJECT //otherwise the EF will try to create a new one //...so lets find the one that matches the type name the user selected PROCESS_OBJECT_TYPE pot = db.PROCESS_OBJECT_TYPE.First(d => d.OBJECT_TYPE_ID == process_object.PROCESS_OBJECT_TYPE.OBJECT_TYPE_ID); //assign it to the process_object process_object.PROCESS_OBJECT_TYPE = pot; //lets not forget to add the type_id or EF will complain about it process_object.OBJECT_TYPE_ID = pot.OBJECT_TYPE_ID; db.PROCESS_OBJECT.AddObject(process_object); db.SaveChanges(); //GridRouteValues() is an extension method which returns the //route values defining the grid state - current page, sort expression, filter etc. RouteValueDictionary routeValues = this.GridRouteValues(); // add the editing mode to the route values routeValues.Add("mode", mode); return RedirectToAction("EditingServerSide", routeValues); } PopulateJobTypes(); //The model is invalid - render the current view to show any validation errors return View("EditingServerSide", db.PROCESS_OBJECT.Include("PROCESS_OBJECT_TYPE")); } [AcceptVerbs(HttpVerbs.Post)] public ActionResult Save(int id, string name, GridEditMode mode, GridButtonType type, bool? pageInput, bool? nextPrevious, bool? numeric, GridPagerPosition? position, int? currentPage, bool? pageSize) { setViewData(mode, type, pageInput, nextPrevious, numeric, position, currentPage, pageSize); PROCESS_OBJECT process_object = new PROCESS_OBJECT(); //Perform model binding (fill the product properties and validate it). //Exclude "PROCESS_OBJECT_TYPE from the list of updated properties if (TryUpdateModel(process_object)) { //Need to get this cloned object to update the real one in the entity context. //Need to attach an existing PROCESS_OBJECT_TYPE entity from the database to this new PROCESS_OBJECT //otherwise the EF will try to create a new one //...so lets find the one that matches the type name the user selected PROCESS_OBJECT_TYPE pot = db.PROCESS_OBJECT_TYPE.First(d => d.OBJECT_TYPE_ID == process_object.PROCESS_OBJECT_TYPE.OBJECT_TYPE_ID); //assign it to the process_object process_object.PROCESS_OBJECT_TYPE = pot; //lets not forget to add the type_id or EF will complain about it process_object.OBJECT_TYPE_ID = pot.OBJECT_TYPE_ID; //Through trial and error I found that on update the object is in fact already loaded //but I had to manually mark the previously detached object as modified db.ObjectStateManager.ChangeObjectState(process_object, EntityState.Modified); //...then use this method to actually apply the changes... //Without doing both this, the object never updates in the database db.SaveChanges(); //GridRouteValues() is an extension method which returns the //route values defining the grid state - current page, sort expression, filter etc. RouteValueDictionary routeValues = this.GridRouteValues(); // add the editing mode to the route values routeValues.Add("mode", mode); return RedirectToAction("EditingServerSide", routeValues); } PopulateJobTypes(); //The model is invalid - render the current view to show any validation errors return View("EditingServerSide", db.PROCESS_OBJECT.Include("PROCESS_OBJECT_TYPE")); } private void PopulateJobTypes() { ViewData["process_object_types"] = db.PROCESS_OBJECT_TYPE.Select(e => new { Name = e.OBJECT_TYPE_NAME, Id = e.OBJECT_TYPE_ID }) .OrderBy(e => e.Name); } } }Thanks