【问题标题】:ASP.NET MVC EntityFramework lazy loading or ViewModel?ASP.NET MVC 实体框架延迟加载还是 ViewModel?
【发布时间】:2015-02-01 20:40:05
【问题描述】:

要理解我的意思,要考虑的最佳示例是 ASP.NET MVC 上的简单“MyBlog”。我有来自表 AuthorPostComment 的数据库。如果我需要将一些 Post 传递到视图中并显示它的 Author 和所有 Comments,最佳做法是什么?使用 EntityFramework 延迟加载 或使用所有必需的数据创建 ViewModel

还有一个问题要问我: 如果是 ViewModel,我应该为每个视图使用它,还是只为此创建,需要一些额外的数据吗?或者我不明白使用 ViewModel 的想法?

提前感谢您的部分体验:)

【问题讨论】:

    标签: c# asp.net asp.net-mvc entity-framework viewmodel


    【解决方案1】:

    您应该总是(几乎总是)为不同的操作使用不同的ViewModels(即使ViewModel 描述了相同的Entity)。事实证明,您不需要在所有操作中获取有关Entity 的所有信息。假设您的Post 实体包含:ICollection<Comment> - 当您的视图不显示时,您真的需要获取 cmets(或查询不需要的字段)吗?

    您还问过创建ViewModels 的目的是什么——这是将数据返回到View 的常用和标准方式。返回适当填充的ViewModel 而不是数据库Entity 将防止Lazy Load 异常和错误。即使您超出了数据库范围,您的视图也可能会访问延迟加载的字段(因为您的数据库查询可能没有加载该字段 - 因为您不需要它)。

    使用ViewModel 而不是数据模型Entity 对象的另一个原因是,有时需要格式化数据库中的数据以显示(例如,具有正确日期格式而不是 DateTime 的字符串属性 - string CreatedDate { get; set; } )。你当然不想用那个来膨胀你的 Entity 类。

    顺便说一句:我建议您查看AutoMapper 库,它可以帮助您自动将属性从Entity“复制”到ViewModel,而不是手动执行此操作。

    【讨论】:

    • 如果我要把所有额外的信息放到 ViewModel 中,我需要 ViewBag 做什么?
    • @Mutex 老实说 - 你根本不应该使用它。如果你设计了合适的 ViewModel - 就不需要 ViewBag。
    【解决方案2】:

    我会给你我对事物的“看法”。几乎所有视图都使用的 ViewModel。不要偷懒,就这样吧。

    所以创建 ViewModel,用你需要的变量填充它,然后在 Controller 中填充变量。

    稍后,当您开始使用 AutoMapper 或类似的先进技术时,您就会明白为什么。

    关于你原来的问题:

    class PostViewModel
    {
        public string Author { get; set; }
    
        public List<Post> Posts { get; set; }
    }
    

    这有帮助还是我需要详细说明?

    顺便说一句,我不使用延迟加载。我使用它,但 99% 的时间我调用 Include() 以确保我拥有数据。

    【讨论】:

    • 但是如果在Controller中填充ViewModel,就不会瘦了。
    • 这就是为什么稍后你会使用 AutoMapper 和 Ninject 等等。几个月前我开始使用它们,所以我理解你。现在让它工作,以后你会让它更漂亮......
    【解决方案3】:

    您绝对应该使用 ViewModel 来分隔上下文,正如 MVC 模式所暗示的那样。在您的场景中,我可能会使用我计划在各种视图中使用的所有属性的总和来创建一个功能齐全的 ViewModel,并仅使用 DbContext 的实体项中的相应值填充每个特定视图所需的那些。

    这是一个简短的例子:

    public ActionResult Edit(int? id = null) 
    {
        Room r = UnitOfWork.GetContext().Rooms
            .Where(i => i.ID == id.Value).FirstOrDefault();
        RoomViewModel rvm = new RoomViewModel();
        rvm.ID = r.ID;
        rvm.Name = rvm.Name;
        if (needToBindChildren) rvm.ChildItems = r.ChildItems;
        return View(rvm);
    }
    

    除了让您的代码干净且符合 MVC 之外,使用 ViewModel 的另一个优势是您可以将它用作您最终需要执行的任何请求的主要 POST 参数(基本上,每个以 html 表单为特色的视图):

    [HttpPost]
    public ActionResult Edit(RoomViewModel rvm)
    {
        string name = rvm.Name;
        int id = rvm.ID;
        UpdateRoomName(id, name);
    }
    

    您可以手动绑定属性或使用您选择的映射器(EmitMapper、Ninject、AutoMapper 等),具体取决于您的需要。

    LazyLoading 功能在您的场景中并不真正相关,因为您很可能想要 Load()Include() 在您需要时使用您的属性,并在不需要时避免使用它们。

    有关启用、禁用和有效使用 LazyLoading 功能的快速参考指南,我建议您参考以下参考资料:

    【讨论】:

      【解决方案4】:

      您问的是两个不同的概念。实体框架是在 SQL 样式数据库上运行的 ORM(对象关系映射)层。 ViewModel 是一个架构概念,它使用一个包含与当前视图相关的所有数据和行为的对象。您确实没有理由选择其中一个,两者都可能与您正在做的事情相关。

      您是从数据库加载对象吗?这些都是通过 Entity Framework 完成的(通常会关闭延迟加载,它真的不会为您带来太多收益,并且可能会花费您更多的数据库调用)。

      当需要将数据呈现给用户时,它应该在视图模型中。该模型是传递给视图的。它应该包括与该视图相关的任何内容(用户、页面、相关记录的数量、可能来自其他来源的一些其他信息),并且通常可以包括来自实体框架的实体副本。

      除非您正在执行 CRUD(创建、检索、更新、删除)视图,否则 在您的视图和实体之间断开连接,而这种断开连接就是视图模型的来源. 一个做得好的 MVC 应用实际上更接近于 MVVMC(模型视图 VewiModel 控制器),其中控制器选择一个 ViewModel 并告诉它它需要知道什么来与模型对话并获取它的数据。然后将该 ViewModel 传递给 View。因此,对于您的应用程序而言,控制器只不过是一个路由器。

      【讨论】:

      • 延迟加载是有用的技术,不应该仅仅因为“害怕更多的数据库调用”而被禁用。只有使用不当才会花费更多的数据库调用。
      • @fex 问题在于启用或禁用延迟加载还不是很清楚。 SQL 请求中的典型开销不是数据访问(尽管有时可能),而是网络堆栈和线路。这是否意味着延迟加载没有有用的案例?不,但它在大多数情况下并不适用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多