如何使用ToDataSourceResult(),IQueryable的剑道UI电网 ,视图模

2019-09-02 12:09发布

什么是加载/过滤/订购剑道网格下面的类的最佳方法:

域:

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

视图模型

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));

...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))

好吧,电网负荷完美的第一次,但是当我过滤/ ORDER BY IsActiveText我得到以下信息:

无效的属性或字段 - “IsActiveText”类型:汽车

什么是在这种情况下,最好的办法?

Answer 1:

有关的东西似乎不可思议。 你告诉剑道UI,使一格CarViewModel

.Grid<CarViewModel>()

并告诉它有一个IsActive列:

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

CarViewModel没有该名称的列:

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

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

如果你想过滤和排序在数据库中发生的,那么你就需要调用.ToDataSourceResult()上的IQueryable它违背了DB之前。

如果您已经取出所有的Car记录了数据库,那么你可以先做你的映射解决这个问题,然后调用.ToDataSourceResult()IQueryable<CarViewModel>



Answer 2:

我不喜欢剑道已实施“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; }
}

浏览模式:

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; }
}

扩展:

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('_', '.');
    }
}

属性:

[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();
        }
    }
}

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);
    }


Answer 3:

我跟着CodingWithSpike的建议和它的作品。 我创建了DataSourceRequest类的扩展方法:

public static class DataSourceRequestExtensions
    {
        /// <summary>
        /// Finds a Filter Member with the "memberName" name and renames it for "newMemberName".
        /// </summary>
        /// <param name="request">The DataSourceRequest instance. <see cref="Kendo.Mvc.UI.DataSourceRequest"/></param>
        /// <param name="memberName">The Name of the Filter to be renamed.</param>
        /// <param name="newMemberName">The New Name of the Filter.</param>
        public static void RenameRequestFilterMember(this DataSourceRequest request, string memberName, string newMemberName)
        {
            foreach (var filter in request.Filters)
            {
                var descriptor = filter as Kendo.Mvc.FilterDescriptor;
                if (descriptor.Member.Equals(memberName))
                {
                    descriptor.Member = newMemberName;
                }
            } 
        }
    }

然后在你的控制器中,添加using的扩展类和调用ToDataSourceResult()之前,补充一点:

request.RenameRequestFilterMember("IsActiveText", "IsActive");


Answer 4:

弗朗的解决方案是非常好的! 但要小心铸造过滤器来FilterDescriptor。 他们中的一些可以复合。

使用此实施DataSourceRequestExtensions代替弗朗齐歇克年代:

public static class DataSourceRequestExtensions
{
    /// <summary>
    /// Enable flattened properties in the ViewModel to be used in DataSource.
    /// </summary>
    public static void Deflatten(this DataSourceRequest dataSourceRequest)
    {
        DeflattenFilters(dataSourceRequest.Filters);

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

    private static void DeflattenFilters(IList<IFilterDescriptor> filters)
    {
        foreach (var filterDescriptor in filters)
        {
            if (filterDescriptor is CompositeFilterDescriptor)
            {
                var descriptors
                    = (filterDescriptor as CompositeFilterDescriptor).FilterDescriptors;
                DeflattenFilters(descriptors);
            }
            else
            {
                var filter = filterDescriptor as FilterDescriptor;
                filter.Member = DeflattenString(filter.Member);
            }
        }
    }

    private static string DeflattenString(string source)
    {
        return source.Replace('_', '.');
    }
}


Answer 5:

我碰到同样的问题和大量的研究后,我用AutoMapper.QueryableExtensions库永久解决它。 它有一个可以投影手机实体查询到模型之后,你可以在你的预测模型应用ToDataSourceResult扩展方法扩展方法。

public ActionResult GetData([DataSourceRequest]DataSourceRequest request)
{
     IQueryable<CarModel> entity = getCars().ProjectTo<CarModel>();
     var response = entity.ToDataSourceResult(request);
     return Json(response,JsonRequestBehavior.AllowGet);
}

记住使用CreateMap配置Automapper。

注意:这里getCars将返回IQueryable的结果车。



Answer 6:

如果你使用Telerik的数据访问或任何其他支持的IQueryable接口/ ORM您的数据来解决这个问题的一个好方法,就是创建视图直接在你的数据库RDBMS映射一个对一个(有automapper)到您的视图模型。

  1. 创建您要使用的视图模型

     public class MyViewModelVM { public int Id { get; set; } public string MyFlattenedProperty { get; set; } } 
  2. 创建你的SQL Server(或任何RDBMS你正在使用)的列精确匹配视图模型属性名称的看法,当然建立您的视图来查询正确的表。 请确保您有这种观点在你的ORM类

     CREATE VIEW MyDatabaseView AS SELECT t1.T1ID as Id, t2.T2SomeColumn as MyFlattenedProperty FROM MyTable1 t1 INNER JOIN MyTable2 t2 on t2.ForeignKeyToT1 = t1.PrimaryKey 
  3. 配置AutoMapper你的ORM视图类映射到您的视图模型

     Mapper.CreateMap<MyDatabaseView, MyViewModelVM>(); 
  4. 在你的剑道格读取动作,使用该视图构建查询和项目中使用Automapper的ToDataSourceQueryResult

     public ActionResult Read([DataSourceRequest]DataSourceRequest request) { if (ModelState.IsValid) { var dbViewQuery = context.MyDatabaseView; var result = dbViewQuery.ToDataSourceResult(request, r => Mapper.Map<MyViewModelVM>(r)); return Json(result); } return Json(new List<MyViewModelVM>().ToDataSourceResult(request)); } 

这是一个有点开销,但它会帮助你在两个层面上的实现性能与大型数据集时:

  • 您正在使用本地RDBMS的观点,你可以调整自己。 总是会胜过你在.NET中构建复杂的LINQ查询
  • 您可以利用过滤的Telerik的ToDataSourceResult好处,分组,汇总,...


文章来源: How to use Kendo UI Grid with ToDataSourceResult(), IQueryable, ViewModel and AutoMapper?