【问题标题】:Entities lose change-tracking when edited with MVC3使用 MVC3 编辑时,实体会丢失更改跟踪
【发布时间】:2012-03-05 08:39:12
【问题描述】:

我构建了一个非常简单的 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);
}

还有,它不再是一个跟踪代理类。这会导致主键违规,因为实体框架试图将我的对象添加为新对象,而我只希望实体框架检测更改并创建更新语句。哦对了,上面代码中的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; } 
}

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

提前致谢!

【问题讨论】:

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


    【解决方案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);
    }
    

    【讨论】:

    • 听起来会奏效。但这不是“坏”吗?显式设置状态听起来有点脏。
    • @Avalaxy 否。这是附加实体时过程的一部分,因为 EF 不知道实体的状态。存储库应该知道实现细节。
    【解决方案2】:

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

    【讨论】:

    • 是的,存储库由 DI 容器注入到我的控制器中。感谢您的回答,这可能是解决方案。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-13
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 2018-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多