我有一个通用存储库:
public class GenericRepository<TEntity> : AbstractRepository<TEntity>, IRepository<TEntity> where TEntity : class
{
private DbContext _context;
[...]
public GenericRepository(DbContext context)
{
_context = context;
context.Configuration.AutoDetectChangesEnabled = true;
_dbSet = _context.Set<TEntity>();
}
[...]
public void SaveChanges()
{
_context.SaveChanges();
}
[...]
public void Add(TEntity entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_dbSet.Add(entity);
}
[...]
public virtual void Update(TEntity entity)
{
_context.Entry(entity).State = EntityState.Modified;
}
在我的控制器中,有以下代码:
[HttpPost]
public ActionResult Edit(Project project)
{
if (ModelState.IsValid)
{
if (project.Id == 0)
{
ProjectRepository.Add(project);
}
else
{
ProjectRepository.Update(project);
}
ProjectRepository.SaveChanges();
[...]
选择和插入工作正常,但不更新:我得到InvalidOperationException(德语错误消息的英文翻译是“对象状态管理器中已存在具有相同密钥的对象。对象状态管理器无法跟踪多个对象用同一把钥匙。“)。
我不明白,因为我是开发机器上的唯一用户,而且我没有在其他地方修改记录。
知道我在这里做错了吗?
答案 0 :(得分:4)
看看这些答案:
基本上你需要这样做:
var entity = _context.Projects.Find(project.ProjectId);
_context.Entry(entity).CurrentValues.SetValues(project);
希望这有帮助。
答案 1 :(得分:0)
project
实例是由模型绑定创建的,不是从存储库加载的,因此您需要从存储库中实际加载project
实例,然后更改该属性。
答案 2 :(得分:0)
免责声明:我从未使用过Entity Framework,我是基于我对ASP.NET MVC和nHibernate的经验编写的,但你应该能够应用相同的模式
好的,首先你的实际问题实际上是一个双键插入,这是这种情况,因为传递给你的编辑动作的项目对象不是你想要更新的同一个对象(这个对象是从您的模型绑定器基于FormValueProvider中的值)。它可能有相同的值和相同的id,但对于你的ORM来说,它是一个从未被持久存储到数据库的全新对象。
您可以使用以下模式(quick'n脏样本代码)来防止这种情况
[HttpPost]
public ActionResult Edit(Project project)
{
if (ModelState.IsValid)
{
if (project.Id == 0)
{
ProjectRepository.Add(project);
}
else
{
Project dbProject = ProjectRepository.GetById(project.Id); //or whatever your method to retrieve entities by Id is named
UpdateModel(dbProject, "project"); //http://msdn.microsoft.com/en-us/library/dd470933.aspx
ProjectRepository.Update(project);
}
}
}