【问题标题】:Update on Entity fails using generic Repository使用通用存储库更新实体失败
【发布时间】:2012-07-25 10:42:45
【问题描述】:

我有一个通用存储库:

    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(德语错误消息的英文翻译是“对象状态管理器中已存在具有相同键的对象。对象状态管理器无法跟踪多个对象使用相同的密钥。”)。

我不明白,因为我是我的开发机器上唯一的用户,而且我没有在其他地方修改记录。

知道我在这里做错了什么吗?

【问题讨论】:

    标签: c# asp.net-mvc entity-framework repository asp.net-mvc-4


    【解决方案1】:

    看看这些答案:

    基本上你需要这样做:

     var entity = _context.Projects.Find(project.ProjectId);
     _context.Entry(entity).CurrentValues.SetValues(project);
    

    希望这会有所帮助。

    【讨论】:

    • 我想尝试,但由于它是通用存储库,我不能在不覆盖通用方法的情况下使用“_context.Projects”。如何找到要在我的保存方法中使用的 DbSet?
    • 那么为什么不重写泛型方法呢?它是虚拟的,所以应该不是问题。
    • 是的,但这对于所有存储库来说都是多余的代码,我想避免这种情况。
    • 好吧,似乎没有一个简单、可靠和避免冗余的解决方案,所以我现在覆盖每个存储库的更新方法......无论如何,谢谢。
    【解决方案2】:

    project 实例是通过模型绑定创建的,而不是从您的存储库中加载的,因此您需要从存储库中实际加载一个 project 实例,然后更改其属性。

    【讨论】:

    • 我还会重新考虑使用数据库模型作为视图模型,我认为如果经常(大部分时间)将它们保留为 2 个单独的类是有意义的。
    【解决方案3】:

    免责声明:我从未使用过实体框架,我是根据我在 ASP.NET MVC 和 nHibernate 方面的经验编写的,但您应该能够应用相同的模式

    好吧,首先你的实际问题实际上是双键插入,这是因为传递给你的编辑操作的项目对象不是你试图更新的对象(这个对象是从您的模型绑定器基于 FormValueProvider 中的值)。它可能具有 excat 相同的值,因此具有相同的 id,但对于您的 ORM,它是一个全新的对象,从未持久化到数据库中。

    您可以通过使用以下模式来防止这种情况(快速的脏示例代码)

        [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);
                }
            }
        }
    

    【讨论】:

    • 是的,我以类似的方式进行了操作(请参阅接受的答案),但将控制器中的代码放入存储库中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多