我有一个应用程序来存储有关顾问在数据库中的信息。该模型是一个实体框架模型,而数据库表是Consultant,与许多其他表(WorkExperiences,Programs,CompetenceAreas等)有一对多的关系。现在,当我想在View中创建一个新的Consultant对象时,我真的只想将一个Consultant对象作为模型传递给View。但其中之一,我建议(Collection of complex child objects in Asp.Net MVC 3 application?),我不应该这样做,但使用ViewModels代替。其次,也许这就是原因,当我尝试发布Consultant对象时,如果在视图中将它用作模型,我会收到一条错误,指出“EntityCollection已经被初始化”,并且错误的原因似乎是诸如WorkExperiences之类的对象集合。ViewModels和MVC中与实体框架的一对多关系?
所以我的第一个问题是为什么我得到这个错误。
但更重要的是,如果我应该改用ViewModel,我该如何正确地做到这一点?因为我实际上已经尝试了一些东西,并且让它工作。但是...代码很糟糕。任何人都可以告诉我,我应该做什么,而不是让这个工作更干净?
让我告诉你我有什么(即再次工作,但它是一个噩梦codewise):
一开始创建方法:
public ActionResult Create()
{
Consultant consultant = new Consultant();
ConsultantViewModel vm = GetViewModel(consultant);
return View(vm);
}
助手方法来创建“视图模型”(如果这其实是在什么视图模型应该是等):
private ConsultantViewModel GetViewModel(Consultant consultant)
{
ConsultantViewModel vm = new ConsultantViewModel();
vm.FirstName = consultant.FirstName;
vm.LastName = consultant.LastName;
vm.UserName = consultant.UserName;
vm.Description = consultant.Description;
vm.Programs = consultant.Programs.ToList();
vm.Languages = consultant.Languages.ToList();
vm.Educations = consultant.Educations.ToList();
vm.CompetenceAreas = consultant.CompetenceAreas.ToList();
vm.WorkExperiences = consultant.WorkExperiences.ToList();
return vm;
}
的POST Create方法:
[HttpPost]
[ValidateInput(false)] //To allow HTML in description box
public ActionResult Create(ConsultantViewModel vm, FormCollection collection)
{
try
{
Consultant consultant = CreateConsultant(vm);
_repository.AddConsultant(consultant);
_repository.Save();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Helper方法来创建一个顾问对象(这是一个可怕的特别,在那里我有检查的集合不为空,如果用户决定不在这些列表添加任何东西...):
private Consultant CreateConsultant(ConsultantViewModel vm)
{
Consultant consultant = new Consultant();
consultant.Description = vm.Description;
consultant.FirstName = vm.FirstName;
consultant.LastName = vm.LastName;
consultant.UserName = vm.UserName;
if (vm.Programs != null)
foreach (var program in vm.Programs)
consultant.Programs.Add(program);
if (vm.Languages != null)
foreach (var language in vm.Languages)
consultant.Languages.Add(language);
if (vm.Educations != null)
foreach (var education in vm.Educations)
consultant.Educations.Add(education);
if (vm.WorkExperiences != null)
foreach (var workExperience in vm.WorkExperiences)
consultant.WorkExperiences.Add(workExperience);
if (vm.CompetenceAreas != null)
foreach (var competenceArea in vm.CompetenceAreas)
consultant.CompetenceAreas.Add(competenceArea);
return consultant;
}
因此,它仍然有效,但远不如干净,因为如果我可以直接使用Consultant对象(如果不是这样“EntityCollection已经初始化”错误“...)。那我应该怎么做呢?
好的,谢谢。但是为了扮演魔鬼的拥护者(为了理解):如果我没有把Consultant对象的“EntityCollection已经初始化”错误(我仍然不明白)作为模型,那么代码将会如此之多简单。关于id,我可以将id字段留在视图中,对吧? (我一直在使用其他上下文环境中的对象时这样做,有点像NerdDinner的例子)。 – Anders 2011-02-24 09:20:26
至于添加额外的属性,我有时使用分部类来完成(在属性只需要应用程序逻辑,而不是数据库的情况下)...所以我有点了解ViewModels的想法,但在这种情况下仍然不够。 – Anders 2011-02-24 09:22:12
@Anders - 关于将Id从视图中移出 - 这不会阻止恶意用户发布它!而且由于'DOES'这个模型有一个ID,所以模型绑定器会很高兴地把它拿起来,所以你会'有'在那里有一个潜在的安全漏洞。 – Yakimych 2011-02-24 10:15:56