ASP.NET MVC应用程序是否应该直接使用实体框架作为模型?


22

我正在Visual Studio 2013(MVC 5)中构建我的第一个MVC应用程序,但我对设置模型的最佳方法尚不清楚。

我已经从现有数据库中使用代码优先生成了一个实体框架模型。我的第一个直觉是创建一些中间类,这些中间类将成为视图使用的模型,并使这些类与实体框架类一起工作。

当我编写中介类时,我意识到我只是在重新实现EF类已经用偶尔的私有setter或从一种数据类型转换为另一种数据类型所做的许多事情。因此,这似乎是一种浪费。

是否直接将实体框架类用作MVC应用程序的模型是一般规则?还是构建这些中间课程缺少一些好处?



如果您使用代码优先,那么就没有现有的数据库,不是吗?
艾萨克·克莱曼

1
使用EF 6.1+,您可以从现有数据库中生成代码优先模型。请参阅此MSDN文章:msdn.microsoft.com/en-au/data/jj200620.aspx
Mike D.

Answers:


23

在我的应用程序中,我总是使用数据库(实体框架)和MVC的不同模型来分离事物。我也将它们分为不同的项目:

  • Example.Entities-包含我的EF实体和用于访问它们的数据库上下文。
  • Example.Models-包含MVC模型。
  • Example.Web -Web应用程序。同时取决于Example.Domain和Example.Models。

MVC模型不是像域实体那样保存对其他对象的引用,而是将ID作为整数保存。

当对页面的GET请求进入时,MVC控制器执行数据库查询,该查询返回一个实体。我编写了采用域实体并将其转换为MVC模型的“转换器”方法。还有其他方法则相反(从MVC模型到域实体)。然后将模型传递给视图,从而传递给客户端。

当发出POST请求时,MVC控制器将获得MVC模型。转换器方法将其转换为域实体。此方法还执行任何无法表示为属性的验证,并确保如果域实体已经存在,则我们将对其进行更新而不是获取新的。这些方法通常看起来像这样:

public class PersonConverter
{
    public MyDatabaseContext _db;

    public PersonEntity Convert(PersonModel source)
    {
         PersonEntity destination = _db.People.Find(source.ID);

         if(destination == null)
             destination = new PersonEntity();

         destination.Name = source.Name;
         destination.Organisation = _db.Organisations.Find(source.OrganisationID);
         //etc

         return destination;
    }

    public PersonModel Convert(PersonEntity source)
    {
         PersonModel destination = new PersonModel()
         {
             Name = source.Name,
             OrganisationID = source.Organisation.ID,
             //etc
         };

         return destination;
    }
}

通过使用这些方法,我消除了在每个控制器中原本会发生的重复。使用泛型可以进一步消除重复数据。

用这种方式做事有很多好处:

  • 您可以根据特定的视图或操作来自定义模型。假设您有一个人的注册表单,该表单在提交后会创建许多不同的实体(人,组织,地址)。如果没有单独的MVC模型,这将非常困难。
  • 如果我需要向视图传递比仅在实体中可用的信息更多的信息,或者将两个实体组合到一个模型中,那么我的宝贵数据库模型就永远不会被触及。
  • 如果您曾经将MVC模型序列化为JSON或XML,则只会获得序列化的直接模型,而不是链接到该模型的所有其他实体。

好的答案,建议您使用ValueInjector或类似的方法(我个人讨厌自动映射器),而不是手动将属性从一个类映射到另一个类。
罗克兰

1
除了添加单独的答案外,我在这里仅评论说,在DDD实践中,视图的“转换器”和单独的模型将被视为应用程序服务层的一部分。基本上,它使您的域模型可以根据需要变得复杂,同时又可以从应用程序中隐藏这种复杂性。它还使应用程序不必因域模型的更改而被更改。ASL处理翻译。
迈克尔·布朗

因此,您要调用PersonModel中具有的每个模型(即Organization对象)以获取该模型的信息?假设您有一个用于更新人员和组织信息的表格,那么在更新组织时会打个电话吗?我正在使用存储的proc,所以我不能一次发送所有模型的属性以及所有包含模型的属性吗?
发光的

1
您将如何处理映射回集合?在EF6中,这似乎变得更加复杂,因为您不能再使用更新来创建新的实体列表,因为这会重新创建所有内容……
Gerard Wilkinson

2
建议不要使用自己编写的转换器类,而应使用为解决此问题而编写的Automapper库。自2014年以来,它已经成熟了很多!
BenSmith

6

我会说这确实取决于您的应用程序。它只是在做纯CRUD,没有任何业务逻辑吗?然后,我将直接在视图中使用EF模型。

大多数时候,至少涉及一些业务逻辑,然后在数据/ EF模型与视图之间形成一个层可能是一个好主意。在这种情况下,可能需要执行“ CQRS-lite”(请参见下文)并在控制器内外使用不同的模型。在大多数情况下,读取模型比写入模型“麻烦”得多。

但是,如果应用程序包含很多业务逻辑和/或需要扩展很多,我将至少使用CQRS(命令查询责任隔离),DDD(域驱动设计)以及可能的事件源实现其核心。然后,EF可以用作读取模型的外观。

还要记住,您不必为整个应用程序坚持一种策略/模式,某些区域可能是纯CRUD,而其他区域可能包含许多业务逻辑...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.