【问题标题】:Update in Entity Framework using IUnitOfWork使用 IUnitOfWork 更新实体框架
【发布时间】:2018-01-28 21:22:24
【问题描述】:

我正在使用实体框架和IUnitOfWork 不重复代码,我的Add 是好的,问题是做Update

我收到此错误:

附加“ViewModelTicket”类型的实体失败,因为同一类型的另一个实体已经具有相同的主键值。如果图中的任何实体具有冲突的键值,则在使用“附加”方法或将实体的状态设置为“未更改”或“已修改”时,可能会发生这种情况。这可能是因为某些实体是新实体,尚未收到数据库生成的键值。在这种情况下,使用“添加”方法或“已添加”实体状态来跟踪图形,然后将非新实体的状态设置为“未更改”或“已修改”。

我正在使用这个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);
    }
}

IUnitWork 接口:

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

谢谢

编辑

我解决了这个问题。

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

谢谢你们帮助我。

【问题讨论】:

  • 您是否还需要在 DbContext 之上的另一个工作单元,它已经是一个工作单元?它有什么用途?看起来您正试图绕过使用视图模型并将实体直接发送到您的视图。更好的解决方案是实际使用视图模型并将它们映射回实体,而不是整个分离/附加场景。
  • 我关注了这篇文章netcoders.com.br/…

标签: asp.net-mvc entity-framework


【解决方案1】:

插入新实体时不应该生成下一个更高的 Id 吗?

//                                                    vvv
ticket.TicketId = Convert.ToInt32( UnitOfTicket.Max() + 1 );

【讨论】:

  • public int Max() => DbSet.Max(x => x.TicketId) + 1;
  • 那么应该命名为NextNextIdGetById 是如何实现的? (可以在不应该的时候返回null
  • 第一个“if”是知道对象是否存在 if exists then update() else Add()
  • GetById 在上面
  • 尝试用entry.State = state; 改变状态。请参阅:Entity Framework Add and Attach and Entity States
猜你喜欢
  • 2011-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-22
  • 1970-01-01
  • 2010-10-13
  • 1970-01-01
相关资源
最近更新 更多