ViewModel和MVC中的Entity Framework的一对多关系? [英] ViewModels and one-to-many relationships with Entity Framework in MVC?

查看:98
本文介绍了ViewModel和MVC中的Entity Framework的一对多关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在数据库中存储顾问信息的应用程序。该模型是一个实体框架模型,数据库表是咨询与一些其他表(WorkExperiences,Programs,CompetenceAreas等)的一对多关系。现在,当我想在View中创建一个新的Consultant对象时,我只想将一个Consultant对象作为模型传递给View。但是对于其中一个,已经建议我(收集复杂的子对象在Asp.Net MVC 3应用程序?)我不应该这样做,而是使用ViewModels。其次,也许这是原因,当我尝试发布顾问对象(如果在View中使用它作为模型)时,我收到一个错误,指出EntityCollection已经被初始化了,而且错误的原因似乎是



所以我的第一个问题是为什么我收到这个错误。



但更重要的是,如果我应该使用ViewModel,我该怎么做?因为我实际上已经尝试了一些东西,并得到了工作。但是代码很糟糕任何人都可以告诉我应该做什么,而不是让这个工作更干净?



让我告诉你我有什么(再次工作,但是是一个噩梦):



GET创建方法:

  public ActionResult Create( )
{
顾问顾问=新顾问();
ConsultantViewModel vm = GetViewModel(顾问);

return View(vm);
}

帮助方法创建ViewModel(如果这其实是一个ViewModel应该是如此):

  private ConsultantViewModel GetViewModel(顾问顾问)
{
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)] //允许描述框中的HTML
public ActionResult Create(ConsultantViewModel vm,FormCollection collection)
{
try
{
顾问顾问= CreateConsultant(vm);
_repository.AddConsultant(顾问);
_repository.Save();
return RedirectToAction(Index);
}
catch
{
return View();
}
}

创建顾问对象的辅助方法(这是一个特别可怕的是,我必须检查收藏不是null,以防用户决定不在这些列表中添加任何内容...):

 私人顾问CreateConsultant(ConsultantViewModel vm)
{
顾问顾问=新顾问();
consultant.Description = vm.Description;
consultant.FirstName = vm.FirstName;
consultant.LastName = vm.LastName;
consultant.UserName = vm.UserName;

if(vm.Programs!= null)
foreach(vm.Programs中的var程序)
consultant.Programs.Add(program);
if(vm.Languages!= null)
foreach(vm.Languages中的var语言)
consultant.Languages.Add(language);
if(vm.Educations!= null)
foreach(vm.Educations中的var教育)
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);

回报顾问;
}

所以,再次,它的作品,但无处可见,就像我可以直接使用了一个顾问对象(如果不是那个EntityCollection已经被初始化的错误...),那我该怎么办?

解决方案首先,你不应该使用你的实体对象作为viewmodel,因为(我现在可以想到至少两个原因,但还有更多的):


  1. 您不想公开敏感数据,如Id或Password,想像您的顾问有一个 Id ,一个邪恶的用户打开编辑顾问页面,并发回一个不同的 Id ,结果,邪恶的用户将成功更新不同的顾问


  2. 目前,您在视图中显示的内容与您的顾问对象看起来像...但是如果你想添加不是顾问的一部分的额外信息对象(像复选框一样简单)。在这种情况下,您必须重写相当多的代码,创建ViewModel,映射它等等。如果您从头开始遵循ViewModel模式,只需在需要时简单更改。


关于您的代码 - 您可以尝试使用 AutoMapper =http://automapper.codeplex.com/wikipage?title=Nested%20Mappings&referringTitle=Home =nofollow>嵌套映射进行此类转换。即使你不这样做,你的代码可以通过使用预测来做一点清洁。

  private ConsultantViewModel GetViewModel(顾问顾问) 
{
return new ConsultantViewModel
{
FirstName = consultant.FirstName,
LastName = consultant.LastName,
...
vm。 Programs = consultant.Programs.ToList(),
...
};
}

私人顾问CreateConsultant(ConsultantViewModel vm)
{
var consultant = new Consultant
{
描述= vm.Description,
FirstName = vm.FirstName,
...
};

if(vm.Programs!= null)
{
vm.Programs.ForEach(consultant.Programs.Add);
}
...

退货顾问;
}


I have an application for storing information about consultants in a database. The model is an Entity Framework model, and the database tables are Consultant with one-to-many relationships to a number of other tables (WorkExperiences, Programs, CompetenceAreas, etc). Now, when I want to create a new Consultant object in a View, I would really just want to pass a Consultant object as the model to the View. But for one, it has been suggested to me (Collection of complex child objects in Asp.Net MVC 3 application?) that I shouldn't do this, but use ViewModels instead. Secondly, and maybe this is the reason, I get an error saying "The EntityCollection has already been initialized" when I try to post the Consultant object if using it as a model in the View, and the cause of the error seems to be the collections of objects such as WorkExperiences.

So my first question is why I'm getting this error.

But more importantly, if I should instead use a ViewModel, how would I do that properly? Because I have in fact tried something, and got it working. But...the code is awful. Can anyone please tell me what I should be doing instead to get this working more cleanly?

Let me show you what I have (that again works, but is a nightmare codewise):

The GET Create method:

    public ActionResult Create()
    {
        Consultant consultant = new Consultant();
        ConsultantViewModel vm = GetViewModel(consultant);

        return View(vm);
    }

Helper method to create the "ViewModel" (if this is in fact what a ViewModel is supposed to be like):

    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;
    }

The POST Create method:

    [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 method to create a Consultant object (this one is particularly awful, where I have to check that collections are not null, in case the user decides not to add anything in those lists...):

    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;
    }

So, again it works, but is nowhere near as clean as if I could have used a Consultant object directly (if not for that "EntityCollection is already initialized" error"...). So how should I do it instead?

解决方案

First of all, you shouldn't use your entity object as the viewmodel because (and I can think of at least two reasons right now, but there are more):

  1. You don't want to expose sensitive data, such as 'Id' or 'Password'. Imagine your consultant has an Id and an evil user opens the edit consultant page and posts back a different Id. As a result, the evil user will succeed in updating different Consultant.

  2. Currently whatever you show in the View corresponds to what your Consultant object looks like. But in case you want to add extra info that is not part of the Consultant object (as simple as a checkbox field). In that case, you have to rewrite quite a bit of code, create the ViewModel, map it, etc. While if you follow the ViewModel pattern from the start, you can just make this simple change whenever you need it.

Regarding your code - you can try to use AutoMapper with Nested Mappings for this type of conversion. Even if you don't, your code can be made a bit cleaner by using projections.

private ConsultantViewModel GetViewModel(Consultant consultant)
{
    return new ConsultantViewModel
               {
                   FirstName = consultant.FirstName,
                   LastName = consultant.LastName,
                   ...
                   vm.Programs = consultant.Programs.ToList(),
                   ...
               };
 }

 private Consultant CreateConsultant(ConsultantViewModel vm)
 {
     var consultant = new Consultant
                      {
                          Description = vm.Description,
                          FirstName = vm.FirstName,
                          ...
                       };

     if (vm.Programs != null)
     {
         vm.Programs.ForEach(consultant.Programs.Add);
     }
     ...

     return consultant;
}  

这篇关于ViewModel和MVC中的Entity Framework的一对多关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆