1

我有一个表单可以更新一个包含大约 10 个字段的实体,但是创建这个特定的表单是为了只更新其中的三个字段。到目前为止我看到的所有示例,在提交整个数据时都使用了 SaveChanges() 方法。提交部分数据导致我的实体将所有其他字段替换为 NULL。我找到的解决方案是在我的视图页面上添加 7 个隐藏参数,但我很确定有一种更优雅的方法可以做到这一点。我是 MVC4 的新手,任何关于这个问题的教程都会非常有帮助。谢谢

我试过这个:

        tblEmployee CurrentEmployee = model.EmployeeToDisplay;


        try{
            var ChosenEmployee = emp.SpecifiEmployee(Id);//retrieve selected employee
            CurrentEmployee.IsNew = false;
            CurrentEmployee.StatusID = 1;
            ChosenEmployee.ShortId = CurrentEmployee.ShortId;
            db.Entry(ChosenEmployee).State = EntityState.Modified;
            db.SaveChanges();
        }

但我得到一个错误: An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

4

2 回答 2

3

您可以创建仅包含该表单中可编辑字段的视图模型。

然后在保存更改时,您需要从数据库中检索实体,将视图模型中的字段映射到检索到的实体,最后调用 SaveChanges。

因此,给定实体FooEntity,您可以创建一个EditFooViewModel仅包含要编辑的属性的视图模型:

public class FooEntity
{
    public int Id {get; set;}
    public string Field1 {get; set;}
    public string Field2 {get; set;}

    public string NonEditableField1 {get; set;}
    public string NonEditableField2 {get; set;}
}

public class EditFooViewModel
{
    public int Id {get; set;}
    public string Field1 {get; set;}
    public string Field2 {get; set;}
}

然后在提交表单时,检索实体并使用视图模型值更新它,然后再保存更改。保持示例简单,遵循此想法的控制器方法可能如下所示:

public ActionResult SaveChanges(EditFooViewModel viewModel)
{
    ... check model state for errors...

    //Get the current entity value
    var entity = dbContext.FooEntities.Single(e => e.Id == viewModel.Id);

    //Map values from view model to entity
    entity.Field1 = viewModel.Field1;
    entity.Field2 = viewModel.Field2;

    //Save changes 
    dbContext.SaveChanges();

    ...
}

编辑 - 我什么时候应该使用视图模型?

视图模型将帮助您将控制器/视图与业务层分离。这意味着视图模型可以为您的业务对象提供不同的视图(在单个视图模型中组合多个实体,减少暴露的属性或注意格式化数据!)并且它们将减少对业务层的更改所产生的影响在控制器/视图上,反之亦然。(从简单的更改(例如重命名后端的属性)到更大的更改,例如将业务层公开为 REST json 服务)

它们还将阻止您将任何不需要的属性公开为隐藏字段,或手动将可编辑属性设置为已修改(这与遵循视图模型模式的映射代码非常相似!)。如果您有任何将实体返回为 json 的操作,您还可以避免暴露整个业务对象。另一个好处是,当您忘记在 EF(或您可能正在使用的其他后端)中手动附加和设置修改的属性时,您可以防止细微的错误

确实,它们增加了自己的一些复杂性,主要是一组额外的类(视图模型)以及对视图模型-模型映射代码的需求。(尽管这里有一些工具可以提供帮助,比如 Automapper)

还要考虑到对于许多应用程序,将控制器/视图与后端分离是一项要求。在这些情况下,视图模型是可行的方法。

我还要说,在我看来,与替代方案相比,使用视图模型时添加的额外代码并不算多:

  • 您可以决定为验证中涉及的任何其他字段使用隐藏字段(因此验证成功),然后将模型附加到 EF 上下文,手动设置可编辑属性为已修改。您不需要视图模型类和映射代码,并且您还可以防止额外的数据库命中以在保存之前检索当前实体值。但是,您需要视图中的隐藏字段,以及将每个可编辑属性设置为在 EF 中修改的代码。不要忘记,如果有任何新的验证,您可能需要在视图中添加一个新的隐藏字段。

  • 另一种选择是根本不使用隐藏字段,并且仅在视图中显示您实体中的可编辑字段。保存时,您需要从 EF 中检索实体,手动映射可编辑字段,最后验证并保存。这与使用视图模型几乎相同,但没有视图模型类。在验证和保存之前,您仍然需要从后端检索实体并映射视图中编辑的属性!虽然这在某些情况下可能就足够了,但在其他情况下,您还需要使用视图模型的好处。

然而,这并不意味着您应该在每个应用程序上盲目地使用视图模型。是您知道您的具体场景和要求,因此您需要考虑每种选择的优缺点,并决定哪一种最有意义!

于 2013-09-17T14:00:55.853 回答
0

SaveChanges 是来自 EntityFramework 吗?

在调用 saveChanges 之前,您可能只是检索您的数据,并且只更新您想要的字段。如果不查看您的控制器或查看您如何获取/处理数据,很难给出准确的示例。

但我想它会是这样的。

...
var myEntity = dbContext.MyEntities.Single(i=> i.Id);
//update only the fields you want updated
dbContext.SaveChanges();
于 2013-09-17T13:43:42.243 回答