- @using (Html.BeginForm(null,null,FormMethod.Post,new { enctype = "multipart/form-data" }))
- {
- @Html.ValidationSummary(true)
- <fieldset>
- <legend>Consultant</legend>
- <div class="editor-label">
- @Html.LabelFor(model => model.FirstName)
- </div>
- <div class="editor-field">
- @Html.EditorFor(model => model.FirstName)
- @Html.ValidationMessageFor(model => model.FirstName)
- </div>
- <div class="editor-label">
- @Html.LabelFor(model => model.LastName)
- </div>
- <div class="editor-field">
- @Html.EditorFor(model => model.LastName)
- @Html.ValidationMessageFor(model => model.LastName)
- </div>
- <div class="editor-label">
- @Html.LabelFor(model => model.Description)
- </div>
- <div class="editor-field">
- @Html.TextAreaFor(model => model.Description)
- @Html.ValidationMessageFor(model => model.Description)
- </div>
- <div class="editor-label">
- Program du behärskar:
- </div>
- <div>
- <table id="programEditorRows">
- <tr>
- <th>
- Program
- </th>
- <th>
- Nivå
- </th>
- </tr>
- @foreach (var item in Model.Programs)
- {
- Html.RenderPartial("ProgramEditorRow",item);
- }
- </table>
- <a href="#" id="addProgram">Lägg till</a>
- </div>
- <div class="editor-label">
- Språk du behärskar:
- </div>
- <div>
- <table id="languageEditorRows">
- <tr>
- <th>
- Språk
- </th>
- <th>
- Nivå
- </th>
- </tr>
- @foreach (var item in Model.Languages)
- {
- Html.RenderPartial("LanguageEditorRow",item);
- }
- </table>
- <a href="#" id="addLanguage">Lägg till</a>
- </div>
- <div>
- <table id="educationEditorRows">
- <tr>
- <th>
- Utbildning
- </th>
- <th>
- Nivå
- </th>
- </tr>
- @foreach (var item in Model.Educations)
- {
- Html.RenderPartial("EducationEditorRow",item);
- }
- </table>
- <a href="#" id="addEducation">Lägg till</a>
- </div>
- <div>
- <table id="workExperienceEditorRows">
- <tr>
- <th>
- Arbetserfarenhet
- </th>
- <th>
- Startdatum
- </th>
- <th>
- Slutdatum
- </th>
- </tr>
- @foreach (var item in Model.WorkExperiences)
- {
- Html.RenderPartial("WorkExperienceEditorRow",item);
- }
- </table>
- <a href="#" id="addWorkExperience">Lägg till</a>
- </div>
- <div>
- <table id="competenceAreaEditorRows">
- <tr>
- <th>
- Kompetensområde
- </th>
- <th>
- Nivå
- </th>
- </tr>
- @foreach (var item in Model.CompetenceAreas)
- {
- Html.RenderPartial("CompetenceAreaEditorRow",item);
- }
- </table>
- <a href="#" id="addCompetenceArea">Lägg till</a>
- </div>
- <div>
- <input id="fileInput" name="FileInput" type="file" />
- </div>
- <p>
- <input type="submit" value="Spara" />
- </p>
- </fieldset>
- }
- <div>
- @Html.ActionLink("Back to List","Index")
- </div>
这是GET Edit方法:
和POST编辑方法:
现在,当AutoMapper创建viewmodel时,它似乎工作正常(使用其最简单的形式,没有解析器或任何东西,只是将Consultant映射到Consultantviewmodel),包括子集合和所有.此外,UserName属性在那里.现在,在视图中我没有UserName的字段,因为它总是由当前用户(User.Identity.Name)自动填充.但是当我返回vm时,UserName属性为null,可能是因为View中没有该字段.
我怀疑一些集合会导致相同的错误,即使我在那里为UserName放置一个隐藏字段,因为它是可选的,以便顾问填写语言等…所以即使viewmodel有一个实例化的列表,每个这些子集合进入View(计数为0),它们返回时返回null值.
我该如何解决这个问题?我不想强迫用户在所有子集合中填充值.我的意思是,我总是可以为Name属性创建一个带有空字符串的Language对象,但这意味着不必要的额外代码,我真正想要的是让孩子集合(和UserName)回到他们进入的方式.视图 – 填写UserName,并且实例化子集合,但如果用户未添加任何项目,则计数为0.
更新:
我不知道,我认为我在某种程度上误解了AutoMapper ……我发现实际上子集合在映射方面确实不是问题,它可以很好地将它映射回Consultant对象.但是……我还需要将id放回Consultant对象中,因为viewmodel没有.但即便如此,当我保存到存储库时,它也不会被保存.这就是我认为我误解了AutoMapper的地方 – 我曾经以为它会以某种方式用viewmodel中的值填充Consultant对象,但我想它会导致顾问变量引用Map()语句中的另一个对象?因为没有一个坚持……
- [HttpPost]
- [ValidateInput(false)] //To allow HTML in description Box
- public ActionResult Edit(int id,FormCollection collection)
- {
- vm.UserName = User.Identity.Name;
- Consultant consultant = _repository.GetConsultant(id);
- consultant = Mapper.Map<Consultantviewmodel,Consultant>(vm);
- consultant.Id = id;
- _repository.Save();
- return RedirectToAction("Index");
- }
我究竟做错了什么?如何将viewmodel中的填充值返回到Consultant对象并将其保存到数据库?
更新2:
好吧,彻底迷茫…开始有点:这是Application_Start中的地图创建:
编辑方法:
- // GET: /Consultant/Edit/5
- public ActionResult Edit(int id)
- {
- Consultant consultant = _repository.GetConsultant(id);
- Consultantviewmodel vm = Mapper.Map<Consultant,Consultantviewmodel>(consultant);
- return View(vm);
- }
- //
- // POST: /Consultant/Edit/5
- [HttpPost]
- [ValidateInput(false)] //To allow HTML in description Box
- public ActionResult Edit(int id,FormCollection collection)
- {
- vm.UserName = User.Identity.Name;
- Consultant consultant = _repository.GetConsultant(id);
- consultant = Mapper.Map<Consultantviewmodel,Consultant>(vm,consultant);
- _repository.Save();
- return RedirectToAction("Index");
- }
这也不起作用,但显然至少会尝试更新实体模型,因为现在我得到一个例外:
无法初始化EntityCollection,因为EntityCollection所属的对象的关系管理器已附加到ObjectContext.只应调用InitializeRelatedCollection方法在对象图的反序列化期间初始化新的EntityCollection.
- Line 698: if ((value != null))
- Line 699: {
- Line 700: ((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<Program>("ConsultantsModel.ConsultantProgram","Program",value);
- Line 701: }
- Line 702: }
这与我在尝试直接将实体对象用作模型时获得的错误完全相同,而不是让AutoMapper创建viewmodel.那么我做错了什么?这真让我抓狂…
更新3:
好吧,无尽的故事……我在AutoMapper的CreateMap方法中找到了一些使用UseDestinationValue的信息.所以我试过了,好吧,实际上让我更进一步.但是……现在我在SaveChanges()上获得了一个新例外(在EF模型中).现在的例外是:“操作失败:由于一个或多个外键属性不可为空,因此无法更改关系.”这似乎是一个异常,如果您没有级联删除集,当尝试删除一对多关系中的子对象时也会发生异常,但这不是我在这里尝试做的…
这是更新的CreateMap方法:
有任何想法吗?
解决方法
我改变它,以便我现在为子集合中的每个类型都有一个DTO对象(可能应该在使用AutoMapper时开始使用它).例如,我现在有一个ProgramDTO类型与Program一起映射.
我尝试使用Consultant对象进行映射,希望嵌套集合能够自行运行,但只能再次出现“EntityCollection已初始化”错误.所以在预感中我尝试了这种方法:
- private Consultant CreateConsultant(Consultantviewmodel vm,Consultant consultant) //Parameter Consultant needed because an object may already exist from Edit method.
- {
- Mapper.Map(vm,consultant);
- //To do this I had to add an Ignore in the mapping configuration:
- //Mapper.CreateMap<Consultantviewmodel,Consultant>().ForMember(x => x.Programs,opts => opts.Ignore());
- //Delete items "marked for deletion" by removing with jQuery in the View:
- var programs = consultant.Programs.Except(consultant.Programs.Join(vm.Programs,p => p.Id,d => d.Id,(p,d) => p)).ToList();
- Delete(programs);
- foreach (var programDto in vm.Programs)
- {
- Program program = consultant.Programs.SingleOrDefault(x => x.Id == programDto.Id);
- if (program == null)
- {
- program = new Program();
- consultant.Programs.Add(program);
- }
- program = Mapper.Map(programDto,program);
- }
- _repository.Save();
- return consultant;
- }
不同之处在于我通过UpdateModel()填充Consultant的简单属性,然后遍历ProgramDTO集合并映射每个程序.
这很有用,虽然我不太喜欢这个代码……在我这样做之后它也打了我,我还需要能够删除用户“标记为删除”的任何项目,可以这么说在视图中.我正在使用一个视图,您可以按照Steven Sanderson的教程,通过jQuery添加和删除文本框等.但是这使得代码变得更加复杂……无论如何,这是我能想到的最好的,所以如果你能改进这个,请再提供任何其他想法!我特别希望有一个解决方案,我不需要在POST上手动循环集合,但让AutoMapper处理嵌套集合本身,没有上面提到的错误!