ASP.NET MVC EntityFramework 延迟加载还是 ViewModel?

ASP.NET MVC EntityFramework lazy loading or ViewModel?

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

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

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

我会给你我的 "View" 东西。几乎所有视图都使用 ViewModel。别偷懒,照着做。

因此创建 ViewModel,用您需要的变量填充它,然后在 Controller 中填充变量。

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

关于你原来的问题:

class PostViewModel
{
    public string Author { get; set; }

    public List<Post> Posts { get; set; }
}

这有帮助还是我需要了解更多细节?

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

您问的是两个不同的概念。 Entity framework 是在 SQL 风格的数据库上运行的 ORM(对象关系映射)层。 ViewModel 是一个架构概念,它使用一个包含与当前视图相关的所有数据和行为的对象。真的没有理由你应该选择一个或另一个,两者都可能与你正在做的事情相关。

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

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

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

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

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

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

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

您绝对应该使用 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 功能的快速参考指南,我建议您参考以下内容: