如何在 MVC5 中访问 Kendo UI 网格内的实体框架域对象

Posted

技术标签:

【中文标题】如何在 MVC5 中访问 Kendo UI 网格内的实体框架域对象【英文标题】:How do I access an Entity Framework domain object inside of a Kendo UI Grid in MVC5 【发布时间】:2015-08-21 11:54:11 【问题描述】:

我是 Web 开发、C# 和 .net (VS2013) 的新手,我不确定我是否正确地问了这个问题,但是在搜索了书籍、所有 Telik 文档和谷歌搜索之后,我仍然卡在一些东西上很简单。

我想要做的是使用 Kendo Grid 和 Ajax 在 MVC 应用程序中创建一个页面,以显示有关客户端位置的信息,并包括来自不同数据库表的主 phone.number 和主 address.add1,在网格。

我的域对象

public partial class location

    public location()
    
        this.addresses = new HashSet<address>();
        this.location_note = new HashSet<location_note>();
        this.phones = new HashSet<phone>();
    
    public long id  get; set; 
    public long acct_id  get; set; 
    public Nullable<bool> active  get; set; 
    public string name  get; set; 
    public string contact  get; set; 
    public Nullable<long> location_account_id  get; set; 

    public virtual ICollection<address> addresses  get; set; 
    public virtual ICollection<location_note> location_note  get; set; 
    public virtual ICollection<phone> phones  get; set; 


public partial class address

    public long id  get; set; 
    public long acct_id  get; set; 
    public long location_id  get; set; 
    public bool primary  get; set; 
    public string add1  get; set; 
    public string add2  get; set; 
    public string city  get; set; 
    public string county  get; set; 
    public string state  get; set; 
    public string zip  get; set; 
    public string comment  get; set; 
    public long address_type_id  get; set; 

    public virtual address_type address_type  get; set; 
    public virtual location location  get; set; 


public partial class phone

    public long id  get; set; 
    public long acct_id  get; set; 
    public long location_id  get; set; 
    public bool primary  get; set; 
    public long phone_type_id  get; set; 
    public string number  get; set; 

    public virtual location location  get; set; 
    public virtual phone_type phone_type  get; set; 

我的脚手架位置控制器

public class LocationController : Controller

    private vessenceEntities db = new vessenceEntities();

    public ActionResult Index()
    
        return View();
    

    public ActionResult locations_Read([DataSourceRequest]DataSourceRequest request)
    
        IQueryable<location> locations = db.locations;
        DataSourceResult result = locations.ToDataSourceResult(request, location => new 
            id = location.id,
            acct_id = location.acct_id,
            active = location.active,
            name = location.name,
            contact = location.contact,
            location_account_id = location.location_account_id,
        );

        return Json(result);
    

我的视图 - Index.cshtml

@(Html.Kendo().Grid<VEPrototype.location>()
  .Name("grid")
  .Columns(columns =>
  
    columns.Bound(c => c.acct_id);
    columns.Bound(c => c.active);
    columns.Bound(c => c.name);
    columns.Bound(c => c.contact);
    columns.Bound(c => c.location_account_id);
    )
  )
  .ToolBar(toolbar => 
        toolbar.Create();
        toolbar.Excel();
        toolbar.Pdf();
  ) 
  .Editable(editable => editable.Mode(GridEditMode.PopUp))
  .Pageable()
  .Sortable(sortable => 
      sortable.SortMode(GridSortMode.MultipleColumn);
  )
  .Filterable()
  .Scrollable()
  .DataSource(dataSource => dataSource
      .Ajax()
      .Model(model => model.Id(p => p.id))
      .Read(read => read.Action("locations_Read", "Location"))
  )

我尝试做的事情:

    当我在 LocationController 中进行调试停止时,我在 IQueryable 位置变量中看不到任何数据,只是查询 - 但如果我执行 ToList(),那么我可以在每个位置看到正确的地址。所以我尝试将值添加到 json 结果到视图中,例如:

    primaryaddress = location.addresses.GetElementAt(0).add1
    

    只是想看看我能不能拿回一些东西 - 行不通。似乎即使我将额外的地址和电话数据添加到 Json 结果中,视图也与位置模型相关联,因此我无法访问我添加的那些额外数据,这是有道理的。那么我是否需要将视图与我将在其他地方构建的不同模型相关联,并在网格中添加我想要的位置、地址和电话数据?

    我尝试使用 PrimaryAddress 和 PrimaryPhone 属性创建另一个位置部分类,并在该类中通过位置类中的地址执行 foreach - 但是当 getter 运行时,地址尚未填充,我获取空引用异常。

当使用标准 razor 语法和 VS 脚手架控制器时,我可以在视图中看到整个位置域对象,并通过每个位置的地址找到每个位置的主要地址和电话。在将 Kendo Grid 与 Ajax 一起使用时,我遇到了麻烦,它将 Json 传递给视图,而我不知道如何将地址和电话数据放入视图中。抱歉,这可能是基本的,如果有人可以向我指出一些有关使用 Kendo 控件的最佳实践的文档,它可能会帮助我摆脱困境。我已经搜索并浏览了 Telerik 网站,但我发现的 Ajax/Json 示例仅从数据库中的一个表中提取数据,这已经与脚手架组件配合得很好。

提前谢谢...

【问题讨论】:

【参考方案1】:

我没有时间在这里给出完整的答案,但有几件事是最重要的...... IQueryable 是一个延迟执行接口,这意味着查询实际上不会运行,直到您调用类似 .ToList()查询,见here。其次,我建议考虑可能使用AutoMapper,以便您可以将数据传输对象(客户端模型)与持久保存到数据库的对象(实体模型)分开(如果映射很简单,您也可以在不使用 Automapper 的情况下进行此映射) .考虑到这两点,您可以在一个上下文中测试 DTO 和客户端绑定,并在另一个上下文中测试控制器到实体绑定,从而消除一些魔力。

编辑#1:

以下是使用 OData 进行实体到 DTO 映射的示例:

    [EnableQuery]
    public IQueryable<FooDto> Get()
    
        // Load set into read-only context for performance.
        var sets = Context.Foos.AsNoTracking();
        // AutoMapper will modify the database query to support exposing DTOs
        var setsDtos = sets.Project().To<FooDto>();
        return setsDtos;
    

或者这里是使用 OData 的单个结果的案例:

    [EnableQuery]
    public SingleResult<FooDto> Get(string key)
    
        return
            SingleResult.Create(
                Context.Foos.AsNoTracking().Where(set => set.FooId == key)
                    .Project()
                    .To<FooDto>()
                    .AsQueryable());
    

【讨论】:

Bill - 谢谢,听起来我需要创建一些模型类来控制视图中显示的内容并将剑道网格绑定到这些类。然后创建一个对象服务层,它将查询我的域对象,提取我需要的数据并填充将发送到视图的模型类(AutoMapper 应该在那里提供帮助 - 谢谢你)。然后在数据从视图回发时执行相反的操作,将数据从模型对象中拉出以填充域对象,然后让 EF 持久化数据。那是对的吗?我想我认为还有更多的魔法。 可以有更多的魔力,但每次我试图将我的 DTO 持久化回数据库时,我都会后悔并最终放置了一个映射层......部分用于测试,部分用于给我一个地方可以做一些事情,比如展平子集合或复合多个聚合根以使 javascript 更干净。也就是说,采用这种方法,您可以在没有任何痛苦或间接性的情况下做一些非常巧妙的事情。明天我会尝试用一些示例编辑我的帖子,以帮助您入门。 感谢比尔的这些编辑 - 它有助于消除一些迷雾。

以上是关于如何在 MVC5 中访问 Kendo UI 网格内的实体框架域对象的主要内容,如果未能解决你的问题,请参考以下文章

Kendo UI Hierarchical datagrid - 如何从详细网格编辑器模板 MVVM 访问根视图模型

记住在 Kendo-UI 中刷新时扩展的细节网格

如何在 kendo ui 网格中选择关键行

弹出窗口在 Kendo UI 网格中的工作原理以及如何在 MVC4 的 Kendo UI ajax 网格中将控件带入弹出窗口

Angular 的 Kendo UI:如何在网格中定义最小宽度

如何根据 kendo ui mvc 网格中的条件格式化行