我试图了解整个MVC / EF关系。如果我创建一个只与数据库交互的实体模型(因为你不应该将实体模型传递给视图),那么Model的类,最后是一个视图模型,如下所示。我唯一的问题是拥有第二个类似乎是多余的,我看到的例子中唯一不同的是它们将数据注释应用于该类,因为它与视图交互。为什么确保实体对象不暴露在视图层是如此重要?
我还没有真正开始编写项目,但是我假设您将使用Entity模型与数据库进行交互,然后将其转换为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; }
}
答案 0 :(得分:3)
有时候,特别是在简单模型上,可能不需要视图模型。但是,和一个大型的#34;但是,我发现很少有这种情况的实例,即便如此,我后来普遍发现需要回头创建一个视图模型,无论如何。拥有专业的视图模型更安全,更简单,更容易全面。
你可能会把它视为额外的工作,但从关注点的分离(这是MVC的重点)来考虑它。例如,如果我想为输入提供SelectList,我可以将其添加到ViewBag或我的模型。如果我将它添加到ViewBag,我会失去强类型,这绝不是理想的,但它也不属于我的数据库跟踪实体。有了一个视图模型,让我把这些信息准确地放在应该去的地方:一个强类型模型,它可以为视图提供服务,只为视图提供服务。
或者,考虑验证:如果我想要数据库所需的字段(非空)该怎么办,但是我想让用户选择这个,如果用户选择,请在幕后填写一些业务逻辑不要说明。视图模型可以轻松处理该抽象,而将其添加到实体本身会增加大量复杂性。
当然,没有必要。你可以随时设置你的项目,但最好的做法是最好的做法,原因是:开发人员喜欢你,一次又一次,遇到了同样的问题,并围绕一个可行的解决方案进行了合并。您可能会暂时避开视图模型,但最终,您会遇到相同的障碍并将其合并到一起,所以只需从一开始就做到这一点,让您的生活更轻松。
答案 1 :(得分:1)
我创建一个与我的实体分开的模型类有两个主要原因。
正如您所提到的,属性。您可能希望在多个应用程序中重用您的实体,并且它们可能不使用相同的属性。您不希望用这些污染您的实体。
根据它们的不同,您的实体可能需要基类。或者可能存在必须应用于实体的属性或其他自定义。这可能会导致在测试业务逻辑时遇到困难。此外,如果您更改ORM更改中的ORM或某些内容,您将保持该更改与应用程序的其余部分隔离。
基本上,您正在隔离应用程序的不同层,并保护一层不受另一层的更改。
答案 2 :(得分:1)
您需要Product class
,ProductViewModel class
,然后是DbContext
。
如果您是第一次这样做,请阅读Pro ASP.NET MVC 3 Framework, Third Edition
或
他们有关于MVC的详细信息,这两本书从头到尾都有Real Application tutorial you can follow
,包括部署。
您还将学习单元测试和其他MVC工具,例如依赖注入(Ninject)和Moq
答案 3 :(得分:1)
除了上面的答案之外,还没有提到另一个要点,以防止数据被发送到不需要的视图/客户端。
例如,假设您的产品型号包含您向供应商支付的购买产品的价格。您不希望您的客户看到此数据,但如果它包含在发送到视图的模型中 - 即使您没有显示该字段 - 他们也可以对其进行评估。在这种情况下,您将使用不同的视图模型并将数据从ef /数据库模型复制到视图模型,然后再将其发送到视图。有时您最终会得到一个DBcontext类,一个EF /数据库类/模型和几个视图模型,每个视图模型都包含数据库模型中不同的数据子集。
你也可以找到一个包含来自多个数据库模型的数据的viewmodel,你可以看到这个视图使用列表或下拉列表作为在viewbag中发送列表选项的替代方法。
答案 4 :(得分:1)
ViewModel将实际传递到浏览器或从浏览器传递,通常是通过JSON,如果您正在构建可以就地更新/保存到位的东西。所以:
ASP.Net MVC对JSON可以产生/消耗的内容有一些限制(其限制在每个方向上略有不同);您可以使用ViewModel来解决
从数据库中提取的数据大小可能不是需要访问浏览器的数据 - 例如,您可能需要撤回一些额外的字段并在传递之前检查它们,但只需要传递子集 - ViewModel是子集。
JSON中的某些自然结构在数据库中确实不可用 - 例如,您可能具有存储在模型中的等效词典,例如,一个表具有一些值,另一个表具有FK指向回到它,一个Id和一个字符串值 - 但是为了让浏览器利用它,您可能只需要该字符串值。因此,在ViewModel中,您可以使用简单的Dictionary(最终作为客户端上的简单JS对象)来表示所有这些。
像日期格式化这样的东西常常在客户端上很弱或者根据具有准确系统时钟等的客户端而变得脆弱。我经常在我的ViewModel中使用String,我在模型中有一个DateTime并从中翻译UTC到他们的时区,并在它到达浏览器之前在服务器上很好地格式化。
有时您需要避免将模型的某些部分暴露给浏览器;例如,在某些系统中,如果将行Id暴露给浏览器,则可能会产生安全风险。 ViewModel可以隐藏模型的部分内容。
答案 5 :(得分:0)
首先,有一些缺失和组合技术,一个是从所有其他层完全抽象DAL,这是一种技术。但也有其他技术可以使用;使用“实体”类作为域类。在一个简单的场景中,我们总是使用业务层上的域类来应用所有业务规则。这将有助于我们在层中结合可测试性并避免层之间的无用链接,而不会增加大量代码行/类数。
这种在所有层中使用这个域对象(域类)的方法在使用MVC时会使事情变得更加容易,因为这些类可以包含将被以下内容使用的数据注释:
另外,为了理解这类课程的概念和用法,我们需要注意一些事项。如果我们使用POCO作为我们的实体和域类,那么这些相同的类与Entity Framework在向DB解释查询时将使用的类不同。相反,EF将创建动态类(从POCO派生),将动态类表示为一个实体并加载所有虚拟字段,通常是相关实体。
您将保存类的代码和简单的重新映射。
希望这有帮助
答案 6 :(得分:-1)
为什么确保实体对象不会在视图层公开?
不是。对于简单的CRUD控制器,通常更容易传入实体对象。对于更复杂的页面,您可能同时与多个Entity对象/类型进行交互。如何在不创建新模型类的情况下传递有关两个对象的信息?