使用MVC3编辑时,实体会丢失更改跟踪

时间:2012-02-13 22:37:06

标签: c# asp.net-mvc-3 entity-framework frameworks entity

我构建了一个非常简单的MVC3应用程序来做一个小小的演示,但我遇到了一个问题。我将一个实体返回到我的视图,编辑它然后将其发回,但在此过程中,我的实体失去了它的变更跟踪功能。当我将实体返回到我的视图时,它仍然是一个实体框架代理类,但当它从我的视图中返回时,它是一个'Person'类(该实体被称为person)。

这是我的存储库类:

public class PersonRepository : IPersonRepository
{
    public EfContext Uow { get; set; }

    public PersonRepository(IUnitOfWork uow)
    {
        Uow = uow as EfContext;
    }

    // yada yada yada

    public void Add(Person person)
    {
        Uow.Persons.Add(person);
    }
}

此实体被发送到我的视图,该视图具有使用Html.EditorForModel创建的简单表单。之后我将其发回给这个方法:

[HttpPost]
public ActionResult Edit(Person person)
{
    if (ModelState.IsValid)
    {
        _personRepository.Add(person);
        _personRepository.Uow.Commit();

        return RedirectToAction("Index");
    }

    return View(person);
}

而tada,它不再是一个被跟踪的代理类。这会导致主键冲突,因为实体框架正在尝试将我的对象添加为新对象,我只希望实体框架检测更改并创建更新语句。哦顺便说一句,上面代码中的Commit方法只调用SaveChanges(),这里是类:

public class EfContext : DbContext, IUnitOfWork
{
    public DbSet<Account> Accounts { get; set; }
    public DbSet<Person> Persons { get; set; } 

    public void Commit()
    {
        SaveChanges();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}

顺便说一句,这是我的实体类:

public class Person
{
    [HiddenInput(DisplayValue = false)]
    public Guid Id { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public virtual ICollection<Account> Accounts { get; set; } 
}

有谁知道如何解决这个问题?据我所知,我之前有这个工作,我只是不知道如何。

提前致谢!

3 个答案:

答案 0 :(得分:2)

我假设您正在为每个请求创建存储库(在构造函数中或者作为IoC框架的依赖项传递)。在这种情况下,您在控制器方法中收到的实体确实没有被跟踪,因为它是在不同的请求中创建的。您必须将其“附加”到上下文并将其标记为已修改,以便EF知道它已更改并且需要将其保存到数据库

答案 1 :(得分:1)

在您的资源库中定义一个Update方法,该方法将附加实体并将其标记为已修改。

public class PersonRepository : IPersonRepository
{
    // yada yada yada

    public void Add(Person person)
    {
        Uow.Persons.Add(person);
    }

    public void Update(Person person)
    {
        Uow.Persons.Attach(person);
        Uow.Entry(person).State = EntityState.Modified;
    }
}

[HttpPost]
public ActionResult Edit(Person person)
{
    if (ModelState.IsValid)
    {
        _personRepository.Update(person);
        _personRepository.Uow.Commit();

        return RedirectToAction("Index");
    }

    return View(person);
}

答案 2 :(得分:0)

这里有第三种解决方案,我相信这是最安全的解决方案。

您可以配置MVC操作以接收id整数。然后,使用该整数,从数据库中检索实体。然后在控制器上调用UpdateModel方法。这会将新的表单值绑定到现有对象,而不会更改表单中可能没有的未更改的属性和属性。