我无法理解,如何使用TryUpdateModel并同时保存MVC架构。
如果我没弄错,使用datacontexts必须在模型中。所以,这样的代码
var db=new TestEverybody();//it is class, which was generated by EntityFramework
var currentTesting=db.Testing.(t => t.id == id).First();
必须位于模型中,而不是控制器中,不是吗?
但TryUpdateModel用法的示例如下:
public ActionResult Edit(Testing obj)//Testing collection
{
var db = new TestEverybody();
var currentTesting=db.Testing.(t => t.id == obj.id).First();
TryUpdateModel(currentTesting);
db.SaveChanges();
return RedirectToAction("Index");
}
这不会破坏MVC架构吗?我们在控制器中使用数据库,而不是在特殊的Model类中。
那么,在真实项目中使用TryUpdateModel的最佳方法是什么?
答案 0 :(得分:112)
由于OP问,这是一个ViewModel模式的例子,或者我喜欢称之为 - ASP.NET MVC正确完成。
那么为什么要使用视图特定模型
我们将从一个简单的实体开始:
public class Product {
public int Id {get;set;}
public string Name {get;set;}
public string Description {get;set;}
public decimal Price {get;set;}
}
让我们假设您有一个简单的表单,用户可以 更新产品的Name
和Description
。但是你正在使用(非常贪婪的)TryUpdateModel。
所以我使用任意数量的工具(如Fiddler)自己构建一个POST并发送以下内容:
名称= WhatverIWant&安培;描述= UnluckyFool&安培;价格= 0
ASP.NET MVC模型绑定器将检查输入表单集合,看到您的实体上存在这些属性并自动为您绑定它们。因此,当您刚刚从数据库中检索到的实体上调用“TryUpdateModel”时,将更新所有匹配的属性(包括Price!)。是时候换新选择了。
public class EditProductViewModel {
[HiddenInput]
public Guid Id {get;set;}
[Required]
[DisplayName("Product Name")]
public string Name {get;set;}
[AllowHtml]
[DataType(DataType.MultilineText)]
public string Description {get;set;}
}
这只包含我们在视图中需要的属性。请注意,我们还添加了一些验证属性,显示属性和一些mvc特定属性。
不受我们在视图模型中的限制,它可以使您的视图更清晰。例如,我们可以通过在视图中包含以下内容来渲染我们的整个编辑表单:
@Html.EditorFor(model => model)
Mvc将检查我们添加到视图模型中的所有属性,并自动连接验证,标签和正确的输入字段(即用于描述的文本区域)。
[HttpPost]
public ActionResult EditProduct(EditProductViewModel model) {
var product = repository.GetById(model.Id);
if (product == null) {
return HttpNotFound();
}
// input validation
if (ModelState.IsValid) {
// map the properties we **actually** want to update
product.Name = model.Name;
product.Description = model.Description;
repository.Save(product);
return RedirectToAction("index");
}
return View(model)
}
从这段代码中可以看出它的作用。我们更新实体时没有任何不良影响,因为我们在实体上明确设置了属性。
我希望这能够解释View-Model模式,足以让你想要使用它。
答案 1 :(得分:19)
那么,这样的代码必须位于模型中,而不是在Controller中,不是吗?
不一定。我个人更喜欢将数据访问代码放在存储库中。然后使用构造函数注入将一些特定的存储库实现传递给控制器(例如,如果我使用EF,我会编写一个EF存储库实现)。因此控制器将如下所示:
public class HomeController: Controller
{
private readonly IMyRepository _repository;
public HomeController(IMyRepository repository)
{
_repository = repository;
}
public ActionResult Edit(int id)
{
var currentTesting = _repository.GetTesting(id);
TryUpdateModel(currentTesting);
_repository.SaveChanges();
return RedirectToAction("Index");
}
}