如何在ASP.NET MVC 3中更新EF 4实体?

7

我有两个项目 - 一个包含EDM实体框架模型的类库和一个独立的ASP.NET MVC项目。

我在使用MVC编辑和保存实体时遇到了问题。在我的控制器中,我有以下代码:

public class UserController : Controller
    {
        public ActionResult Edit(int id)
        {
            var rep = new UserRepository();

            var user = rep.GetById(id);

            return View(user);
        }

        [HttpPost]
        public ActionResult Edit(User user)
        {
            var rep = new UserRepository();

            rep.Update(user);

            return View(user);
        }
    }

我的UserRepository有一个如下的更新方法:

public void Update(User user)
{
     using (var context = new PDS_FMPEntities())
     {
         context.Users.Attach(testUser);
         context.ObjectStateManager.ChangeObjectState(testUser, EntityState.Modified);
         context.SaveChanges();
     }
}

现在,当我在编辑用户页面上点击“保存”时,参数user只包含两个填充的值:Id和FirstName。我认为这是因为在视图中我只显示了这两个属性。

我的问题是,如果我要更新用户的FirstName并想保存它,由于其他未在视图中显示的User属性现在包含0或NULL值,我该怎么做呢?

我一直在阅读有关使用存根实体的内容,但我一无所获,因为我看到的所有示例都没有运作,即我不断遇到实体键相关的异常。

有人能指向一个好的教程/示例,说明如何使用由MVC前端调用的存储库类来更新EF 4实体吗?

6个回答

2

我会从数据库中检索用户并更新该实体。EF并不能神奇地知道哪些值应该被修改,哪些不应该。

如果您担心并发问题,您需要在视图中存储时间戳 - 通常作为隐藏表单值。


1

经过一些试错,我似乎已经找到了解决方案。这是我在UserRepository中更新的Update方法:

public void Update(User user)
{
    using (this.Context)
    {
        var tempUser = new User { usr_id = user.usr_id };

        this.Context.Users.Attach(tempUser);
        this.Context.ApplyCurrentValues("Users", user);
        this.Context.SaveChanges();
    }
}

我尝试过的其他示例与上述示例非常接近,但仅仅错过了目标。


2
@Jason Evans - 这被称为存根技术,仅适用于标量属性。如果您有一个导航属性(例如User.Addresses),并且您正在将其绑定到视图中,则上述方法不会更新地址。我建议您再次从数据库中检索用户,然后使用TryUpdateModel来更新对象。有关更多信息,请参见我的最近的问题/答案:https://dev59.com/E2445IYBdhLWcg3w4-Be#4666466 - RPM1984
@RPM1984 - 这会减少与导航属性相关的问题。我对TryUpdateModel()唯一关心的是设计问题。我试图确保我可以使用一个仓储来处理获取/保存/删除东西。通过使用TryUpdateModel(),您有建议如何编写良好设计的代码吗?我的意思是我不想控制器处理任何与数据库相关的代码。 - Jason Evans
不,我不确定你的意思。不过我猜你是想在你的Repository中创建一个标准的“保存”方法,该方法可以根据ID(例如)“判断”对象是新的还是已存在的。这样你就不需要调用repository.Update或repository.Add了。只需尝试TryUpdateModel然后保存Save即可。如果你指的是你不希望你的控制器触及你的实体 - 我不明白你的担忧。控制器的作用是刷新模型。它所做的一切只是更新一个“对象” - 你的repository仍然关注于该对象的持久性。 - RPM1984
@RPM - 我刚刚尝试了一段代码示例,你的建议效果很好。可能我的设计顾虑不过是缺乏对MVC的经验,但我会继续进行这个项目,看看使用TryUpdateModel()会怎样。 - Jason Evans
1
没错 - 相信我,我最近一直在做很多 ef/mvc。因为我使用的是没有更改跟踪的 POCO(这意味着没有自跟踪实体,没有代理对象等),所以更新关系非常困难。咬紧牙关,再次获取记录。或者如果您只更新立即属性上的基本属性,则 ApplyCurrentValues 就可以了。但是您需要保持一致。祝好运。 :) - RPM1984
@RPM1984的存根与导航一起很好地工作。只有ApplyCurrentValues是标量。 - Craig Stuntz

0

0

这可能有点晚了,无法回答问题,但也许可以帮助其他人。我认为你遇到的主要问题是由于读取实体的数据库上下文实例在页面呈现后被释放所导致的。因此,当您尝试保存它时,这是一个新的上下文实例,因此对先前上下文调用没有任何了解。因此,Entity Framework必须更新数据库中的所有行,因为它无法知道哪些行已更改。

话虽如此,我发现保存所有旧数据并更新我想要更改的最佳方法是首先对数据库进行新的调用,将Model(或您用于存储数据的任何内容)所需的所有信息设置为当前DB中的信息。然后对该信息进行必要的更改,然后将结果保存到DB中。

您可以查看此处有关实现基本CRUD的教程,以获取更多信息: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-basic-crud-functionality-with-the-entity-framework-in-asp-net-mvc-application


0

我发现asp.net网站上这个教程非常有帮助:使用MVC更新相关数据的EF入门

需要注意的方法是TryUpdateModel,它会以“标准”的方式更新相关模型(将实体设置为修改状态并传递所有内容),然后您可以自定义如何更新某些属性。

我遇到了实体键的问题,这个教程帮助我克服了这些问题。


1
感谢您的输入。我会将这个作为关于EF的资源列表之一。非常感谢。 - Jason Evans

0

2
嘿,如果您能够包含该链接的重要摘录,那就太好了。 - bool.dev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接