【问题标题】:Entity Framework and the relationship with MVCEntity Framework 与 MVC 的关系
【发布时间】:2013-03-28 18:16:39
【问题描述】:

我试图了解整个 MVC/EF 关系。如果我创建一个仅与数据库交互的实体模型(因为您不应该将实体模型传递给视图),然后是模型的类,最后是视图模型,如下所示。我唯一的问题是拥有第二个类似乎是多余的,我所看到的示例中唯一的不同是它们将数据注释应用于该类,因为它与视图交互。为什么确保实体对象不暴露在视图层如此重要?

我还没有真正开始编写项目,但我假设您将使用实体模型与数据库进行交互,然后将其转换为 ProductModel 以传递给视图,这是正确的逻辑吗?

实体模型:

public class Product 
{
    [Key()]
    public int ID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public double Price { get; set; }
}

型号:

public class ProductModel
{
    public int ID { get; set; }
    [StringLength(50)]
    [Required(ErrorMessage = "Product Name is required.")]
    [Display(Name = "Product Name")]
    public string Name { get; set; }
    public string Description { get; set; }
    public double Price { get; set; }
}

视图模型:

public class ProductViewModel
{
    Product myProduct { get; set; }\
    //Plus any other properties I may need for the view.
}

更新:

在我一直在阅读的示例中,它们还设置了如下 DBContext。那么 ProductModel 类就没有用了吗?

public class MyAppContext : DbContext
{
    public MyAppContext()
        : base("name=DBConnection")
    { 
    }

    public DbSet<Product> Products { get; set; }

 }

【问题讨论】:

  • 您从哪里读到不应将“实体模型”传递给视图?

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


【解决方案1】:

有时,尤其是在简单模型上,可能不需要视图模型。但是,一个很大的“但是”,我发现这种情况的实例很少,即使那样,我后来通常还是需要返回并创建一个视图模型,无论如何。拥有一个专门的视图模型更安全、更简单、更容易。

您可能将其视为额外的工作,但可以从关注点分离的角度来考虑它(这是 MVC 的全部要点)。例如,如果我想为输入显示一个 SelectList,我可以将它添加到 ViewBag 或我的模型中。如果我将它添加到 ViewBag,我会失去强类型,这从来都不是理想的,但它也不属于我的数据库跟踪实体。有了一个视图模型,让我把这些信息准确地放在它应该去的地方:一个强类型模型,它的存在是为了服务于视图并且只服务于视图。

或者,考虑验证:如果我想要数据库所需的字段(非空)怎么办,但我想让这个对用户来说是可选的,如果用户选择的话,我自己在幕后用一些业务逻辑填充它不指定。视图模型可以轻松处理该抽象,而将其添加到实体本身会增加巨大的复杂性。

当然,什么都不需要。您始终可以随心所欲地设置您的项目,但最佳实践之所以成为最佳实践是有原因的:就像您一样的开发人员一次又一次地遇到相同的问题并围绕一个可行的解决方案进行合并。您可能可以暂时避免使用视图模型,但最终,您会遇到相同的障碍并无论如何都要合并它们,所以从一开始就这样做,让您的生活更轻松。

【讨论】:

    【解决方案2】:

    我创建一个与我的实体分开的模型类有两个主要原因。

    1. 正如您提到的,属性。您可能希望在多个应用程序中重用您的实体,它们可能不会使用相同的属性。您不想用这些污染您的实体。

    2. 根据它们的 ORM,您的实体可能需要一个基类。或者,您可能需要将属性或其他自定义应用于实体。这可能会导致在测试业务逻辑时出现困难。此外,如果您更改了 ORM 或您的 ORM 中的某些内容发生了更改,您将保持该更改与应用程序的其余部分隔离。

    基本上,您是在隔离应用程序的不同层并保护一个层免受另一层的更改。

    【讨论】:

    • 谢谢!那么对于 DBContext,所有其他层是否真的有用?或者这已经结束了?
    • 没有额外的层可能不会有什么坏处,但我认为这是个好主意。
    • 似乎我可以摆脱 ProductModel 类并在视图模型中创建这些属性,但我想这取决于我是否会在几个其他视图模型与否。
    • @user2220986 没错。通常,给定模型、列表、详细信息和编辑可以有 3 个视图。您希望能够为所有 3 个视图使用相同的 ProductModel,同时您可以拥有一个单独的 ViewModel,其中包含每个视图所需的额外信息。
    【解决方案3】:

    您需要Product classProductViewModel class,然后是您的DbContext。 如果您是第一次这样做,请阅读Pro ASP.NET MVC 3 Framework, Third Edition

    Pro Asp.Net Mvc 4

    他们有关于 MVC 的详细信息,两本书从头到尾都有一个Real Application tutorial you can follow,包括部署。

    您还将了解单元测试和其他 MVC 工具,例如依赖注入 (Ninject) 和 Moq

    【讨论】:

      【解决方案4】:

      除了上面的答案之外,还有一点没有提到,以防止数据被发送到不需要的视图/客户端。

      例如,假设您的产品型号包含您向供应商支付的购买产品的价格。您不希望您的客户看到此数据,但如果它包含在发送到视图的模型中 - 即使您不显示该字段 - 他们也可以评估它。在这种情况下,您将使用不同的视图模型并将数据从 ef/数据库模型复制到视图模型,然后再将其发送到视图。

      有时您最终会得到一个 DBcontext 类、一个 EF/数据库类/模型和几个视图模型,每个视图模型都包含来自数据库模型的不同数据子集。

      您还可以发现自己的视图模型包含来自多个数据库模型的数据,您经常会看到视图使用列表或下拉列表作为在视图包中发送列表选项的替代方案。

      【讨论】:

        【解决方案5】:

        ViewModel 将是实际传入/传出浏览器的内容,如果您正在构建可以就地更新/就地保存的东西,通常通过 JSON。所以:

        • ASP.Net MVC 在它可以通过 JSON 生成/使用的内容方面存在一些限制(并且其限制在各个方向上略有不同);你可以使用 ViewModel 来解决这个问题

        • 您从数据库中拉回的数据大小可能不是浏览器需要的 - 例如,您可能需要拉回一些额外字段并在传递之前检查它们,但只传递子集 - ViewModel 是子集。

        • JSON 中的某些自然结构在数据库中并不真正可用 - 例如,您的模型中可能存储了相当于字典的内容,例如一个具有一些值的表和另一个具有 FK 指向的表回到它,一个 Id 和一个字符串值 - 但要让浏览器利用它,您可能只需要那个字符串值。因此,在 ViewModel 中,您使用一个简单的 Dictionary 来表示所有内容(最终在客户端上作为一个简单的 JS 对象)。

        • 通常,诸如日期格式之类的东西在客户端上很弱,或者由于客户端具有准确的系统时钟等而变得脆弱。我经常在我的 ViewModel 中使用一个字符串,而我的模型中有一个 DateTime 并从UTC 到他们的时区并在服务器上很好地格式化它,然后到达他们的浏览器。

        • 有时您需要避免将模型的某些部分暴露给浏览器;例如,在某些系统中,如果您将行 ID 暴露给浏览器,您可能会产生安全风险。 ViewModel 让隐藏模型的某些部分变得很简单。

        另请参阅:how to design ViewModel

        【讨论】:

          【解决方案6】:

          首先,有一些缺少和组合的技术,一个是从所有其他层完全抽象 DAL,这是一种技术。但是还有其他可以使用的技术;使用“实体”类作为域类。在一个简单的场景中,我们总是使用业务层上的域类来应用所有业务规则。这将帮助我们在不增加大量代码行/类数量的情况下通过层来组合可测试性并避免层之间的无用链接。

          此外,在所有层中使用此域对象(域类)的这种方法将使您在使用 MVC 时变得更容易,因为这些类可以具有数据注释,供以下人员使用:

          1. 用于验证的视图
          2. 数据库完整性

          此外,要了解此类类的概念和使用,我们还需要注意一些事项。如果我们使用 POCO 作为我们的实体和域类,那么这些类与 Entity Framework 在解释对 DB 的查询时将使用的类不同。相反,EF 将创建将域对象表示为实体的动态类(派生自 POCO)并加载所有虚拟字段,通常是相关实体。

          您将节省类代码和简单的重新映射。

          希望对你有帮助

          【讨论】:

            【解决方案7】:

            为什么确保实体对象不暴露在视图层如此重要?

            不是。对于一个简单的 CRUD 控制器,通常更容易只传入实体对象。对于更复杂的页面,您可能会同时与多个实体对象/类型进行交互。在不创建新模型类的情况下如何传递有关这两个对象的信息?

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-01-26
              • 2018-03-08
              • 2018-11-24
              • 1970-01-01
              • 1970-01-01
              • 2022-08-02
              相关资源
              最近更新 更多