如何使用Kendo UI Grid与ToDataSourceResult(),IQueryable <T>,ViewModel和AutoMapper?

rGi*_*osa 11 c# asp.net-mvc kendo-ui kendo-grid

使用以下类加载/过滤/订购Kendo网格的最佳方法是什么:

域:

public class Car
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual bool IsActive { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

视图模型

public class CarViewModel
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual string IsActiveText { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

AutoMapper

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

IQueryable的

var domainList = RepositoryFactory.GetCarRepository().GetAllQueryable();
Run Code Online (Sandbox Code Playgroud)

DataSourceResult

var dataSourceResult = domainList.ToDataSourceResult<Car, CarViewModel>(request, 
                          domain => Mapper.Map<Car, ViewModel>(domain));
Run Code Online (Sandbox Code Playgroud)

...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))
Run Code Online (Sandbox Code Playgroud)

好的,第一次网格加载完美,但是当我按照过滤/排序时,IsActiveText我收到以下消息:

无效的属性或字段 - 类型为"IsActiveText":Car

这种情况下最好的方法是什么?

Sko*_*šek 10

我不喜欢Kendo实现"DataSourceRequestAttribute"和"DataSourceRequestModelBinder"的方式,但那是另一个故事.

为了能够按照"展平"对象的VM属性进行筛选/排序,请尝试以下操作:

领域模型:

public class Administrator
{
    public int Id { get; set; }

    public int UserId { get; set; }

    public virtual User User { get; set; }
}

public class User
{
    public int Id { get; set; }

    public string UserName { get; set; }

    public string Email { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

查看型号:

public class AdministratorGridItemViewModel
{
    public int Id { get; set; }

    [Displaye(Name = "E-mail")]
    public string User_Email { get; set; }

    [Display(Name = "Username")]
    public string User_UserName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

扩展:

public static class DataSourceRequestExtensions
{
    /// <summary>
    /// Enable flattened properties in the ViewModel to be used in DataSource.
    /// </summary>
    public static void Deflatten(this DataSourceRequest dataSourceRequest)
    {
        foreach (var filterDescriptor in dataSourceRequest.Filters.Cast<FilterDescriptor>())
        {
            filterDescriptor.Member = DeflattenString(filterDescriptor.Member);
        }

        foreach (var sortDescriptor in dataSourceRequest.Sorts)
        {
            sortDescriptor.Member = DeflattenString(sortDescriptor.Member);
        }
    }

    private static string DeflattenString(string source)
    {
        return source.Replace('_', '.');
    }
}
Run Code Online (Sandbox Code Playgroud)

属性:

[AttributeUsage(AttributeTargets.Method)]
public class KendoGridAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);

        foreach (var sataSourceRequest in filterContext.ActionParameters.Values.Where(x => x is DataSourceRequest).Cast<DataSourceRequest>())
        {
            sataSourceRequest.Deflatten();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ajax数据加载的控制器操作:

[KendoGrid]
public virtual JsonResult AdministratorsLoad([DataSourceRequestAttribute]DataSourceRequest request)
    {
        var administrators = this._administartorRepository.Table;

        var result = administrators.ToDataSourceResult(
            request,
            data => new AdministratorGridItemViewModel { Id = data.Id, User_Email = data.User.Email, User_UserName = data.User.UserName, });

        return this.Json(result);
    }
Run Code Online (Sandbox Code Playgroud)


Cod*_*ike 5

关于这一点似乎很奇怪.你告诉Kendo UI制作一个网格CarViewModel

.Grid<CarViewModel>()
Run Code Online (Sandbox Code Playgroud)

并告诉它有一IsActive栏:

columns.Bound(c => c.IsActive);
Run Code Online (Sandbox Code Playgroud)

但是CarViewModel没有该名称的列:

public class CarViewModel
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual string IsActiveText { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我的猜测是,剑道从CarViewModel向上传递的字段名IsActiveText,但在服务器上正在运行ToDataSourceResult()针对Car对象(一IQueryable<Car>),不具有该名称的属性.映射在过滤和排序后发生.

如果要在数据库中进行过滤和排序,则需要.ToDataSourceResult()在IQueryable对数据库运行之前调用它.

如果您已经Car从数据库中提取了所有记录,那么您可以先通过映射,然后调用.ToDataSourceResult()一个来解决这个问题IQueryable<CarViewModel>.