我有一个像这样的ViewModel:
public class ProductEditModel
{
public string Name { get; set; }
public int CategoryId { get; set; }
public SelectList Categories { get; set; }
public ProductEditModel()
{
var categories = Database.GetCategories(); // made-up method
Categories = new SelectList(categories, "Key", "Value");
}
}
然后我有两个使用此模型的控制器方法:
public ActionResult Create()
{
var model = new ProductEditModel();
return View(model);
}
[HttpPost]
public ActionResult Create(ProductEditModel model)
{
if (ModelState.IsValid)
{
// convert the model to the actual entity
var product = Mapper.Map(model, new Product());
Database.Save(product);
return View("Success");
}
else
{
return View(model); // this is where it fails
}
}
用户第一次进入Create
视图时会看到一个类别列表。但是,如果它们验证失败,则会将View发送回它们,但这次Categories
属性为null。这是可以理解的,因为ModelBinder
如果不在POST请求中则不会持久Categories
。我的问题是,保持Categories
的最佳方法是什么?我可以这样做:
[HttpPost]
public ActionResult Create(ProductEditModel model)
{
if (ModelState.IsValid)
{
// convert the model to the actual entity
var product = Mapper.Map(model, new Product());
Database.Save(product);
return View("Success");
}
else
{
// manually populate Categories again if validation failed
model.Categories = new SelectList(categories, "Key", "Value");
return View(model); // this is where it fails
}
}
但这是一个丑陋的解决方案。我还能坚持下去吗?我不能使用隐藏字段,因为它是一个集合。
答案 0 :(得分:2)
我通常将我的列表(用于下拉列表)实现为只读属性。当View获取值时,属性自包含在返回值所需的内容上。
public SelectList Categories
{
get
{
var categories = Database.GetCategories(); // made-up method
return new SelectList(categories, "Key", "Value");
}
}
如果有必要,您可以从包含已发布并绑定到您的班级实例的ID的属性中获取当前所选项目(即验证失败)。
答案 1 :(得分:2)
我会使用存储库来获取所需的任何数据,并且不认为这是一个丑陋的解决方案:
[HttpPost]
public ActionResult Create(ProductEditModel model)
{
if (!ModelState.IsValid)
{
// manually populate Categories again if validation failed
model.Categories = Repository.GetCategories();
return View(model);
}
// convert the model to the actual entity
var product = Mapper.Map(model, new Product());
Database.Save(product);
// I would recommend you to redirect here
return RedirectToAction("Success");
}
为了进一步重构,我建议你观看Jimmy Bogard的精彩Putting Your Controllers on a Diet视频演示。
答案 2 :(得分:0)
在我的情况下,我有一个BaseModel类,我将所有这些属性列表保存为类属性。
如下例所示:
public IEnumerable<SelectListItem> CountryList
{
get
{
return GetCountryList().Select(
t => new SelectListItem { Text = t.Name, Value = Convert.ToString(t.CountryID) });
}
}
GetCountryList()
是一个向Singleton请求数据的函数。这只会在应用程序生命周期中发生一次
执行此操作的另一种方法是,如果这些列表非常大,那么将使用带有返回SelectListItem的查找表的静态实用程序类。
如果您需要访问不时更改的列表,那么就不要使用Singleton类。