This is a migrated thread and some comments may be shown as answers.

[Solved] Sorting and Filtering Error on Server bound MVC Grid

0 Answers 79 Views
Grid
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Carey
Top achievements
Rank 1
Carey asked on 12 Jul 2011, 09:13 PM
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:
@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
Tags
Grid
Asked by
Carey
Top achievements
Rank 1
Share this question
or