我的理解是,一次只能将一个模型传递给视图。我看到的问题是,我被迫传递实体框架模型,而不是任何将在视图中管理内务管理的模型。这就是我的意思:
您需要创建一个允许某人将Cars提交到数据库的页面。除了表单字段(例如CarName,CarMake,CarYear),您还需要在页面底部有一个名为"记住值和#34;的复选框。在检查时将记得"记住"当用户单击底部的“提交”按钮时,表单值,因此当他们返回所有表单数据时仍然在表单字段中。不用说,这个Remember Values变量不是Entity Framework模型的一部分 - 它只是一个在视图中使用的内务变量。
你们如何处理添加此复选框?感觉它应该是模型的一部分,但我无法向视图发送两个模型。我只是看着这个问题错了吗?你会推荐什么?
.NET 4.5 / MVC 5 / EntityFramework 6
答案 0 :(得分:1)
从技术上讲,如果模型实际上类似于Tuple
,可以向视图发送两个模型:
@model Tuple<SomeEFModel, SomeViewModel>
虽然那有点难看。如果你正在创建一个视图模型,你也可以将它作为Entity Framework模型的组合。类似的东西:
public class SomeViewModel
{
public SomeEFModel EFModel { get; set; }
public string SomeOtherProperty { get; set; }
// other stuff...
}
然后在控制器中构建一个实例并将其发送到模型:
@model SomeViewModel
您甚至可以完全解耦EF模型和视图模型,创建一个自定义视图模型,该模型包含该视图的所有内容,然后在控制器级别转换为/和EF模型。最终,它归结为哪种实现看起来更干净,更易于维护,这可能因环境而异。
编辑另一种选择,如果模型对您所依赖的框架的任何位置都不熟悉,可能会将您的传出和分开模型。要将数据推送到视图,可以使用上面的复合视图模型。但是当数据从视图中返回时,只需使用正常的实体框架模型以及其他附加字段的附加参数:
public ActionResult Edit(int id)
{
// build the view model with the EF model as a property
return View(someViewModel);
}
[HttpPost]
public ActionResult Edit(SomeEFModel model, string someOtherProperty)
{
// here you have an EF model from the view like normal
// plus the additional property (however many you need)
// you can even create a separate view model to collect the other properties
// as long as the names are well defined, the model binder should build both
}
答案 1 :(得分:1)
我总是创建一个额外的模型,我可以在EF模型之间进行转换。 这个附加模型被传递给View并保存了必要的属性,如CarName,Carmake,CarYear,Remember,可能最重要的是,该特定对象的Id。
因此,当用户提交时,此模型将传递给Post方法,您可以在其中提取所有必需的属性。您使用DbContext中的Id获取数据库模型,并使用刚刚传递的值更新属性。
答案 2 :(得分:1)
这是使用ViewModels的好方法。
使用您要在视图中发送/检索的所有属性构建ViewModel。例如:
EF实体
public class Car {
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string Make { get; set; }
public virtual string Year { get; set; }
}
查看模型
public class AddCarViewModel {
public Car Car { get; set; }
public bool RememberValues { get; set; }
}
<强>控制器强>
public class CarController : Controller {
// Constructor....
public ActionResult Add() {
var vm = new AddCarViewModel();
return View(vm);
}
[HttpPost]
public ActionResult Add(AddCarViewModel vm) {
if (ModelState.IsValid) {
_carService.Save(vm.Car);
}
return View(vm);
}
}
另一个好方法是创建域转移对象,它是POCO类,用于保存通过管道传输的数据。例如,在您的业务层中,您可能希望审核对Car模型的任何更改。因此,您可能拥有CreatedBy,CreatedDate,UpdatedBy,UpdatedDate等属性(这些属性通常不会显示给最终用户,但对于存储非常重要)。
所以你要创建以下类:
public class Car {
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string Make { get; set; }
public virtual string Year { get; set; }
public virtual User CreatedBy { get; set; }
public virtual User UpdatedBy { get; set; }
public virtual DateTime CreatedDate { get; set; }
public virtual DateTime UpdatedDate { get; set; }
}
public class CarDTO {
public Guid Id { get; set; }
public string Name { get; set; }
public string Make { get; set; }
public string Year { get; set; }
}
您可以使用AutoMapper等库来映射Car的属性 - &gt; CarDTO:
var car = _carService.GetCarById(id);
var carDTO = Mapper.Map<Car, CarDTO>(car);
这样,您可以使用DTO选择要向您的视图公开的属性。
答案 3 :(得分:1)
首先,您绝对不应该将EF模型直接传递给您的视图,并且您当然不应该直接发布到您的EF模型。这主要是采用不受信任的,未经过计算的输入,并直接将其写入您的数据模型,只需极少的验证。
虽然这可能适用于没有安全性或其他后果的简单模型,但想象一下您允许用户编辑其个人资料信息的情况。此外,想象一下,在他的个人资料中,您还存储了与其订阅信息相关的信息。特制的提交可能会改变他的订阅信息并让他自由访问您的网站,或者更糟糕......
相反,您使用视图模型。除了安全方面,视图模型也很好,因为除了非常简单的CRUD样式站点之外,您的视图要求通常与数据模型要求不同。例如,某个特定字段可能在您的数据模型中可以为空,但您可能希望在视图中使其成为必需字段。如果您直接通过模型,那么就不能轻易做到。
最后,聚合视图模型聚合了许多不同的子模型,以便为视图提供整体模型,这就是您所获得的。然后,您将使用服务层,存储库或业务逻辑层将视图模型转换为数据模型,按摩数据或根据需要应用逻辑。