ASP.NET MVC 实体框架的懒加载还是视图模型?

5
为了理解我的意思,最好考虑一个简单的ASP.NET MVC上的"MyBlog"示例。我有来自AuthorPostComment表的数据库。如果我需要将一些Post传递到视图并显示其Author和所有Comments,最佳实践是什么?使用EntityFramework惰性加载还是创建包含所有必要数据的ViewModel
另外还有一个问题: 如果使用ViewModel,我应该为每个视图使用它,还是只为需要一些额外数据的那个视图创建?或者我可能不理解使用ViewModel的想法?
感谢您提前分享您的经验 :)
4个回答

4
你应该总是(几乎总是)为不同的操作使用不同的ViewModels(即使ViewModel描述相同的Entity)。事实证明,在所有操作中,您并不需要获取有关Entity的所有信息。假设您的Post实体包含:ICollection<Comment>-当您的视图不显示它时,您真的需要获取评论(或查询您不需要的字段)吗?
您还询问了创建ViewModels的目的-这是将数据返回到View的常见和标准方式。返回适当填充的ViewModel而不是数据库Entity将防止Lazy Load异常和错误。即使超出了数据库范围(因为您的数据库查询可能没有加载该字段-因为您不需要它),您的视图也可能访问懒加载的字段。
使用ViewModel而不是数据模型Entity对象的另一个原因是,有时需要将来自数据库的数据格式化以进行显示(例如,具有正确日期格式的字符串属性而不是DateTime- string CreatedDate { get; set; })。您肯定不希望用那个膨胀您的Entity类。
顺便说一下:我建议您查看AutoMapper库,它可以帮助您自动将属性从Entity复制到ViewModel,而不是手动操作。

如果我应该将所有附加信息放入ViewModel中,那么我还需要ViewBag吗? - Mutex
2
@Mutex 说实话 - 你根本不应该使用它。如果你设计了合适的ViewModel - 就没有必要使用ViewBag了。 - fex

2
你应该使用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”功能的快速参考指南,我建议您参考以下参考资料:

2
我会给你我的看法。ViewModel在每个视图中都会用到,请不要懒惰,按照以下方式进行操作。
创建ViewModel,填充所需变量,在控制器中填充变量。
稍后,当您开始使用AutoMapper或类似的进阶功能时,您将明白其中原因。
至于您最初的问题:
class PostViewModel
{
    public string Author { get; set; }

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

这有帮助吗?还是需要更详细的解释?

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


1
但是如果在控制器中填充ViewModel,它就不会很薄了。 - Mutex
1
这就是为什么之后你会使用AutoMapper、Ninject等工具的原因。我几个月前开始使用它们,所以我理解你。现在先让它工作起来,之后再让它更漂亮... - HerGiz

1
您在询问两个不同的概念。Entity Framework是一个运行在SQL风格数据库上的ORM(对象关系映射)层。ViewModel是一个架构概念,使用一个包含当前视图相关所有数据和行为的对象。实际上没有理由让您选择其中一个,两者都可能与您正在做的事情相关。
您是否正在从数据库加载对象?这些通常使用Entity Framework完成(通常关闭惰性加载,因为它并没有太大优势,反而会增加更多的数据库调用)。
当展示数据给用户时,应该使用视图模型。该模型将传递给视图。它应该包括与该视图相关的任何内容(用户、页面、相关记录数、其他可能来自另一个来源的信息),并且通常可以包括从Entity Framework复制的实体。

除非你正在执行CRUD(创建、检索、更新、删除)视图,否则你的视图和实体之间会出现不一致,在这种情况下需要使用视图模型。一个做得好的MVC应用实际上更接近于MVVMC(Model View ViewModel Controller),其中Controller选择ViewModel,并告诉它需要了解哪些内容以便与Model交互获取数据。然后将该ViewModel传递给View。因此,Controller变成了应用程序的路由器。


懒加载是一种有用的技术,不应该仅因为“担心会增加数据库调用次数”而禁用它。只有在使用不当的情况下才会增加更多的数据库调用次数。 - fex
1
@fex 问题在于启用或禁用延迟加载并不是很清楚。 SQL 请求的典型开销不在数据访问中(尽管有时可能会出现),而在网络堆栈和电线中。这是否意味着没有懒加载的有用情况? 不,但大多数情况下并不适用。 - lassombra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接