Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将Kendo UI网格与ToDataSourceResult()一起使用,IQueryable<;T>;,ViewModel和AutoMapper?_C#_Asp.net Mvc_Kendo Ui_Kendo Grid - Fatal编程技术网

C# 如何将Kendo UI网格与ToDataSourceResult()一起使用,IQueryable<;T>;,ViewModel和AutoMapper?

C# 如何将Kendo UI网格与ToDataSourceResult()一起使用,IQueryable<;T>;,ViewModel和AutoMapper?,c#,asp.net-mvc,kendo-ui,kendo-grid,C#,Asp.net Mvc,Kendo Ui,Kendo Grid,加载/过滤/订购具有以下类别的剑道网格的最佳方法是什么: 域: 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

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

域:

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"));
数据源结果

var dataSourceResult = domainList.ToDataSourceResult<Car, CarViewModel>(request, 
                          domain => Mapper.Map<Car, ViewModel>(domain));
var dataSourceResult=domainList.ToDataSourceResult(请求,
domain=>Mapper.Map(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))
…剑道()
.Grid()
.名称(“gridCars”)
.列(列=>
{
columns.Bound(c=>c.Name);
columns.Bound(c=>c.IsActiveText);
})
.DataSource(DataSource=>DataSource
.Ajax()
.Read(Read=>Read.Action(“ListGrid”、“CarsController”))
)
.Sortable()
.Pageable(p=>p.pagesize(真))
好的,网格第一次完全加载,但是当我通过
IsActiveText
过滤/排序时,我得到以下消息:

类型为Car的属性或字段“IsActiveText”无效


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

这似乎有些奇怪。你告诉剑道用户界面为
CarViewModel

.Grid<CarViewModel>()
但是
CarViewModel
没有该名称的列:

public class CarViewModel
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual string IsActiveText { get; set; }
}
我猜Kendo是从CarViewModel
IsActiveText
传递字段名的,但是在服务器上,您针对
Car
对象运行
ToDataSourceResult()
,而这些对象没有该名称的属性。映射发生在过滤和排序之后

如果希望在数据库中进行筛选和排序,则需要在iQueryTable对DB运行之前,在iQueryTable上调用
.ToDataSourceResult()


如果您已经从数据库中取出了所有的
Car
记录,那么您可以通过先进行映射,然后在
IQueryable
上调用
.ToDataSourceResult()
来解决这个问题。我不喜欢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; }
}
视图模型:

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

František的解决方案非常好!但要小心将过滤器投射到过滤器描述器。其中一些可以是复合的

使用此DataSourceRequestExtensions实现,而不是František的:

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('_', '.');
    }
}
公共静态类DataSourceRequestExtensions
{
/// 
///在ViewModel中启用要在数据源中使用的展开属性。
/// 
公共静态无效Deflatten(此DataSourceRequest DataSourceRequest)
{
DeflattenFilters(dataSourceRequest.Filters);
foreach(dataSourceRequest.Sorts中的var sortddescriptor)
{
sortDescriptor.Member=DeflattenString(sortDescriptor.Member);
}
}
专用静态空隙放气过滤器(IList过滤器)
{
foreach(过滤器中的var filterDescriptor)
{
if(filterDescriptor是CompositeFilterDescriptor)
{
变量描述符
=(filterDescriptor作为CompositeFilterDescriptor)。filterDescriptor;
放气过滤器(描述符);
}
其他的
{
var filter=filterDescriptor作为filterDescriptor;
filter.Member=DeflattenString(filter.Member);
}
}
}
私有静态字符串DeflattenString(字符串源)
{
返回源。替换(“”,“);
}
}

如果您在数据上使用Telerik Data Access或任何其他支持IQueryable的接口/ORM,解决此问题的一个好方法是直接在数据库RDBMS中创建视图,将一对一(使用automapper)映射到您的viewmodel

  • 创建要使用的viewmodel

    public class MyViewModelVM
    {
        public int Id { get; set; }
        public string MyFlattenedProperty { get; set; }
    }
    
  • 在SQL Server(或您正在使用的任何RDBMS)中创建一个列与viewmodel属性名称完全匹配的视图,当然,构建视图以查询正确的表。确保在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
    
  • 配置AutoMapper以将ORM视图类映射到viewmodel

    Mapper.CreateMap<MyDatabaseView, MyViewModelVM>();
    
    Mapper.CreateMap();
    
  • 在剑道网格读取操作中,使用视图构建查询,并使用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));
    }
    
    公共操作结果读取([DataSourceRequest]DataSourceRequest请求)
    {
    if(ModelState.IsValid)
    {
    var dbViewQuery=context.MyDatabaseView;
    var result=dbViewQuery.ToDataSourceResult(请求,r=>Mapper.Map(r));
    返回Json(结果);
    }
    返回Json(new List().ToDataSourceResult(request));
    }
    
  • 这有点开销,但在处理大型数据集时,它将帮助您在两个级别上实现性能:

    • 您使用的是本机RDBMS视图,您可以自己进行调优。将始终优于您在.NET中构建的复杂LINQ查询
    • 您可以利用Telerik ToDataSourceResult的过滤、分组、聚合等优点

    我遵循了用Spike编码的建议,它很管用。我为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;
                    }
                } 
            }
        }
    

    我遇到了同样的问题,经过大量研究,我使用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);
    }
    
    public ActionResult GetData([DataSourceRequest]DataSourceRequest请求)
    {
    IQueryable实体=getCars().ProjectTo();
    var response=entity.ToDataSourceResult(请求);
    返回Json(response,JsonRequestBehavior.AllowGet);
    }
    
    请记住使用CreateMap配置AutoMaper


    注意:此处getCars将返回IQueryable结果car。

    初始代码是什么
    Mapper.CreateMap<MyDatabaseView, MyViewModelVM>();
    
    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));
    }
    
    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;
                    }
                } 
            }
        }
    
    request.RenameRequestFilterMember("IsActiveText", "IsActive");
    
    public ActionResult GetData([DataSourceRequest]DataSourceRequest request)
    {
         IQueryable<CarModel> entity = getCars().ProjectTo<CarModel>();
         var response = entity.ToDataSourceResult(request);
         return Json(response,JsonRequestBehavior.AllowGet);
    }