如何使用带有DbContext的ASP MVC更新自定义视图模型

时间:2011-12-05 03:06:29

标签: asp.net-mvc asp.net-mvc-3

我有一个db模型,我想用多个视图编辑它。我的实际数据库模型比我在这里显示的要大得多。

Db模型: PersonModel

public class PersonModel {
    public Int32 Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Description { get; set; }
}

然后我有两个视图, EditPersonName.cshtml EditPersonDescription.cshtml ,使用户能够修改 PersonModel 的不同部分。

查看1: EditPersonName.cshtml

@model EditPersonNameModel
@using (Html.BeginForm()) {
<div class="editor-label">@Html.LabelFor(m => m.FirstName)</div>
<div class="editor-field">@Html.TextBoxFor(m => m.FirstName)</div>
<div class="editor-label">@Html.LabelFor(m => m.LastName)</div>
<div class="editor-field">@Html.TextBoxFor(m => m.LastName)</div>
<input type="submit" value="Save" />
}

查看2: EditPersonDescription.cshtml

@model EditPersonDescriptionModel
@using (Html.BeginForm()) {
<div class="editor-label">@Html.LabelFor(m => m.Description)</div>
<div class="editor-field">@Html.TextBoxFor(m => m.Description)</div>
<input type="submit" value="Save" />
}

我不想将每个视图直接绑定到 PersonModel ,而是希望将它们分别链接到 EditPersonNameModel EditPersonDescriptionModel

查看模型1: EditPersonNameModel

public class EditPersonNameModel {
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

查看模型2: EditPersonDescriptionModel

public class EditPersonDescriptionModel {
    public string Description { get; set; }
}

我想还值得一提的是我正在使用EF的 DbContext 模式。

public class PersonDbContext : DbContext {
    public DbSet<PersonModel> Persons { get; set; }
}

现在为我的控制器,这是事情开始破裂的地方!

控制器: PersonController

public class PersonController {
    private PersonDbContext = new PersonDbContext();

    [HttpGet]
    public ActionResult EditName(int id) {
        // ??? ---- #1 -----
    }

    [HttpPost]
    public ActionResult EditName(EditPersonNameModel model, int id) {
        if (ModelState.IsValid) {
            // ??? ---- #2 ----- ??? Update FirstName,LastName ONLY
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(model);
    }

    [HttpGet]
    public ActionResult EditDescription(int id) {
        // ??? ---- #3 -----
    }

    [HttpPost]
    public ActionResult EditDescription(EditPersonDescriptionModel model, int id) {
        if (ModelState.IsValid) {
            // ??? ---- #4 ----- ??? Update Description ONLY
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(model);
    }

}

我的问题是我不知道在上面的??? ---- #X -----区块放什么。显然,#1#3#2#4非常相似。

有些人建议我使用AutoMapper。这有助于从Db模型到视图模型,但不是相反。

目前,#1的代码块如下所示:

[HttpGet]
public ActionResult EditName(int id) {
    PersonModel person = db.Persons.Find(id);
    if (person == null) {
        return HttpNotFound();
    }
    EditPersonNameModel viewModel;
    AutoMapper.Mapper.CreateMap<PersonModel, EditPersonNameModel>();
    viewModel = AutoMapper.Mapper.Map<PersonModel, EditPersonNameModel>(person);
    return View(viewModel);
}

#2的代码块如下所示:

[HttpPost]
public ActionResult EditName(EditPersonNameModel viewModel, int id) {
    if (ModelState.IsValid) {
        PersonModel person = db.Persons.Find(id);
        if (person == null) {
            return HttpNotFound();
        }
        EditPersonNameModel viewModel;
        AutoMapper.Mapper.CreateMap<EditPersonNameModel, PersonModel>();
        person = AutoMapper.Mapper.Map<EditPersonNameModel, PersonModel>(viewModel);
        db.Entry(person).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(viewModel);
}
上面的

#1实际上工作正常。 AutoMapper将从较大的Person对象映射到EditPersonName对象。

然而,上面的{p> #2已被打破。 AutoMapper将从EditPersonNameModel对象映射到一个新的 Person对象,因此db.Entry(person).State = EntityState.Modified将抛出异常:

  

ObjectStateManager中已存在具有相同键的对象。 ObjectStateManager无法使用相同的键跟踪多个对象。

我不需要AutoMapper来创建新对象,我需要映射到现有对象。如果只有AutoMapper.Mapper. 更新 <EditPersonNameModel, PersonModel>(viewModel, person)

好的,所以这是一个非常长的问题!感谢您的阅读,我非常感谢您的帮助!如果您熟悉AutoMapper并且知道我做错了什么,请告诉我。如果您阅读此代码并了解完全相同的方法,请告诉我们!

谢谢!!!


更新1

我有#2工作,但我不确定它有多好。

#2

[HttpPost]
public ActionResult EditName(EditPersonNameModel viewModel, int id) {
    if (ModelState.IsValid) {
        PersonModel person = db.Persons.Find(id);
        if (person == null) {
            return HttpNotFound();
        }
        TryUpdateModel(person);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(viewModel);
}

请注意TryUpdateModel而不是person会调用viewModel。我已经从数据库中获取了person,所以它已完全填写,带有Id。 TryModelUpdate方法使用IModelBinder将当前“mvc请求上下文”中的属性映射到指定对象。由于我的PersonModelEditPersonNameModel使用相同的命名属性,因此可以使用。这真是一个非常糟糕的解决方案,所以如果你知道更好的东西,请告诉我!

1 个答案:

答案 0 :(得分:2)

我建议使用Automapper或类似解决方案,mvc 3中没有对模型&gt;模型映射的内置支持。