Search code examples
c#asp.net-mvckendo-uikendo-grid

How to use Kendo UI Grid with ToDataSourceResult(), IQueryable<T>, ViewModel and AutoMapper?


What is the best approach to load/filter/order a Kendo grid with the following classes:

Domain:

public class Car
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual bool IsActive { get; set; }
}

ViewModel

public class CarViewModel
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual string IsActiveText { get; set; }
}

AutoMapper

Mapper.CreateMap<Car, CarViewModel>()
      .ForMember(dest => dest.IsActiveText, 
                 src => src.MapFrom(m => m.IsActive ? "Yes" : "No"));

IQueryable

var domainList = RepositoryFactory.GetCarRepository().GetAllQueryable();

DataSourceResult

var dataSourceResult = domainList.ToDataSourceResult<Car, CarViewModel>(request, 
                          domain => Mapper.Map<Car, ViewModel>(domain));

Grid

...Kendo()
  .Grid<CarViewModel>()
  .Name("gridCars")
  .Columns(columns =>
  {
     columns.Bound(c => c.Name);
     columns.Bound(c => c.IsActiveText);
  })
  .DataSource(dataSource => dataSource
     .Ajax()
     .Read(read => read.Action("ListGrid", "CarsController"))
  )
  .Sortable()
  .Pageable(p => p.PageSizes(true))

Ok, the grid loads perfectly for the first time, but when I filter/order by IsActiveText I get the following message:

Invalid property or field - 'IsActiveText' for type: Car

What is the best approach in this scenario?


Solution

  • Something about that seems weird. You told Kendo UI to make a grid for CarViewModel

    .Grid<CarViewModel>()
    

    and told it there is an IsActive column:

    columns.Bound(c => c.IsActive);
    

    but CarViewModel doesn't have a column by that name:

    public class CarViewModel
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual string IsActiveText { get; set; }
    }
    

    My guess is that Kendo is passing up the field name from the CarViewModel IsActiveText, but on the server you are running ToDataSourceResult() against Car objects (an IQueryable<Car>), which do not have a property by that name. The mapping happens after the filtering & sorting.

    If you want the filtering and sorting to happen in the database, then you would need to call .ToDataSourceResult() on the IQueryable before it runs against the DB.

    If you have already fetched all your Car records out of the DB, then you can fix this by doing your mapping first, then calling .ToDataSourceResult() on an IQueryable<CarViewModel>.