我构建了一个非常简单的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; }
}
有谁知道如何解决这个问题?据我所知,我之前有这个工作,我只是不知道如何。
提前致谢!
答案 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方法。这会将新的表单值绑定到现有对象,而不会更改表单中可能没有的未更改的属性和属性。