0

Please advise, I'm using generic repository with UOW, and I got this error when I'm testing my InsertOrUpdate method.(I'm new in both c# and EF)

Result Message:

Test method UnitTestProject1.ManifestUOW.ManifestUOWTest threw exception: System.InvalidOperationException: Attaching an entity of type 'DomainClasses.ManifestDetail' 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.

My generic repository

public T FindById(object id)

    {
        return _set.Find(id);
    }

     public void Add(T entity)
    {
        DbEntityEntry entry = this._ctx.Entry(entity);
        if (entry.State != EntityState.Detached)
        {
            entry.State = EntityState.Added;
        }
        else
        {
            this._set.Add(entity);
        }
    }

    public void Update(T entity)
    {
        DbEntityEntry entry = this._ctx.Entry(entity);
        if (entry.State != EntityState.Detached)
        {
            this._set.Attach(entity);
        }
        entry.State = EntityState.Modified;
    }

    public void InsertOrUpdate(T entity, object id)
    {

        var _Record = FindById(id);
        if (_Record != null)
        {

            Update(entity);

        }
        else
        {
            Add(entity);
        }

    } 

My test implementation

[TestMethod]
    public void ManifestUOWTest()
    {
        ApplicationUOW appUOW = new ApplicationUOW();
        ManifestDetail manD=new ManifestDetail();


        for (var i = 20; i <= 22; i++)
        {

            manD = new ManifestDetail();
            manD.ID = "kkke" + i;
            manD.ManifestID = "kkke";
            manD.ModifiedDate = DateTime.Now;
            manD.PriorityID = 1;
            manD.JobNo = "8888777";
            manD.PartNo = "ppppp";
            manD.OpSeq = "9000";
            manD.QTY = 9;
            manD.Comment = "";
            manD.LitNO = "Lit no";

            appUOW.ManifestDetails.InsertOrUpdate(manD, manD.ID);
        }

        var man = new Manifest();
        man.ID = "kkke";
        man.CreatedDate = DateTime.Now;
        man.ManifestStateID = 2;
        man.MFBldgID = 1;
        man.MFDestBldgID = 2;
        man.UserID = "X6344";

        appUOW.Manifests.InsertOrUpdate(man, man.ID);            
        appUOW.SaveChanges();
 }

My UOW

namespace DataLayer

{

   public class ApplicationUOW:IDisposable

{

   private AuditorStationDB _context = new AuditorStationDB();

   private IRepository<Manifest> _manifests = null;
   public IRepository<Manifest> Manifests
   {
       get
       {
           if (this._manifests == null)
           {
               this._manifests = new GenericRepository<Manifest>(this._context);
           }
           return this._manifests;
       }
   }


   private IRepository<ManifestDetail> _manifestDetails = null;
   public IRepository<ManifestDetail> ManifestDetails
   {
       get
       {
           if (this._manifestDetails == null)
           {
               this._manifestDetails = new GenericRepository<ManifestDetail>(this._context);
           }
           return this._manifestDetails;
       }
   }



   public void SaveChanges()
   {
       this._context.SaveChanges();
   }

   public void Dispose()
   {
       if (this._context != null)
       {
        this._context.Dispose();
       }
   }

}
}
MatthewMartin
  • 32,326
  • 33
  • 105
  • 164
user2662006
  • 2,246
  • 22
  • 16
  • Why does Entity Framework Reinsert Existing Objects into My Database? msdn.microsoft.com/en-us/magazine/dn166926.aspx – Colin May 13 '14 at 04:59
  • @Colin: keeping reading your link, good information :) Thanks – user2662006 May 13 '14 at 17:31
  • You might have a look at my answer on [ASP.NET MVC - Attaching an entity of type 'MODELNAME' failed because another entity of the same type already has the same primary key value](http://stackoverflow.com/questions/23201907/asp-net-mvc-attaching-an-entity-of-type-modelname-failed-because-another-ent/39557606#39557606). – Murat Yıldız Sep 18 '16 at 13:10

1 Answers1

0

The problem you are having is by your InsertOrUpdate() method calling the Update() method.

  1. You first asked EF to locate your entity by Id, so at this point, in EF it is tracking that entity.

  2. Then you pass in the T entity into Update(), in which your Update() method ask it to Attach() it to the EF. Now the EF already tracked a same entity at step 1, you are trying to ask it to Attach() same entity(both entity has same primary key) at step 2, that is why it failed.

So to solve your problem, there is possible 2 ways (not tested):

  1. don't use FindById() to determine InsertOrUpdate() - maybe if id = 0 will mean need insert else update.

  2. before calling Update(), detach your entity FindById() - this._ctx.Entry(entity).State = EntityState.Detached

Although in this article (http://msdn.microsoft.com/en-us/data/jj592676.aspx), it is not talking about Generic repository, but the idea of how to implement InsertOrUpdate method in EF can be found at bottom.

Alan Tsai
  • 2,465
  • 1
  • 13
  • 16
  • 1
    I tried your second possible solution but I still getting same error. please note I already used update else to insert new row (if id==null) in my GenericRepository. Thanks – user2662006 May 13 '14 at 17:25