You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用IUnitOfWork在Entity Framework中更新时遇主键冲突问题

Entity Framework + IUnitOfWork 更新操作报错:相同主键实体已被上下文跟踪

我目前用Entity Framework结合IUnitOfWork模式来减少代码重复,新增(Add)功能正常,但执行更新(Update)时碰到了这个错误:

Attaching an entity of type 'ViewModelTicket' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

我用到的相关代码:

BaseContext类

public class BaseContext<T> : DbContext where T : class {
    public DbSet<T> DbSet { get; set; }
    public BaseContext() : base("DefaultConnection") {
        //Caso a base de dados não tenha sido criada,
        //ao iniciar a aplicação iremos criar
        Database.SetInitializer<BaseContext<T>>(null);
    }
    public virtual void ChangeObjectState(object model, EntityState state) {
        //Aqui trocamos o estado do objeto,
        //facilita quando temos alterações e exclusões
        ((IObjectContextAdapter)this)
            .ObjectContext
            .ObjectStateManager
            .ChangeObjectState(model, state);
    }
    public virtual int Save(T model) {
        this.DbSet.Add(model);
        return this.SaveChanges();
    }
    public virtual int Update(T model) {
        var entry = this.Entry(model);
        if (entry.State == EntityState.Detached)
            this.DbSet.Attach(model);
        this.ChangeObjectState(model, EntityState.Modified);
        return this.SaveChanges();
    }
    public virtual T GetById(object id) {
        return this.DbSet.Find(id);
    }
}

IUnitOfWork接口

public interface IUnitOfWork<T> where T : class {
    int Save(T model);
    int Update(T model);
    void Delete(T model);
    IEnumerable<T> GetAll();
    T GetById(object id);
    int Max();
    IEnumerable<T> Where(Expression<Func<T, bool>> expression);
    IEnumerable<T> OrderBy(Expression<System.Func<T, bool>> expression);
}

控制器方法

public ActionResult SavedTicket(Models.Ticket.ViewModelTicket ticket) {
    if (ModelState.IsValid) {
        if (this.UnitOfTicket.GetById(ticket.TicketId) == null) {
            ticket.TicketId = Convert.ToInt32(
                UnitOfTicket.Max());
            ticket.OpenDateAndTime = DateTime.Now;
            this.UnitOfTicket.Save(ticket);
        } else {
            this.UnitOfTicket.Update(ticket);
        }
        return RedirectToAction(nameof(NewTicket));
    } else {
        return View(nameof(NewTicket), ticket);
    }
}

我自己解决问题的方法:

修改了Update方法,先从上下文获取已跟踪的实体,再把传入的model的值赋值给它:

public virtual int Update(T model, int id) {
    var entity = DbSet.Find(id);
    this.Entry(entity).CurrentValues.SetValues(model);
    return this.SaveChanges();
}

感谢各位的帮助!

内容的提问来源于stack exchange,提问作者lorranpalmeira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:34:02