我有一個應用程序來存儲有關顧問在數據庫中的信息。該模型是一個實體框架模型,而數據庫表是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