[c#] ASP.NET MVC - Attaching an entity of type 'MODELNAME' failed because another entity of the same type already has the same primary key value

In a nutshell the exception is thrown during POSTing wrapper model and changing the state of one entry to 'Modified'. Before changing the state, the state is set to 'Detached' but calling Attach() does throw the same error. I'm using EF6.

Please find my code below(model names have been changed to make it easier to read)

Model

// Wrapper classes
        public class AViewModel
        {
            public A a { get; set; }
            public List<B> b { get; set; }
            public C c { get; set; }
        }   

Controller

        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

            if (!canUserAccessA(id.Value))
                return new HttpStatusCodeResult(HttpStatusCode.Forbidden);

            var aViewModel = new AViewModel();
            aViewModel.A = db.As.Find(id);

            if (aViewModel.Receipt == null)
            {
                return HttpNotFound();
            }

            aViewModel.b = db.Bs.Where(x => x.aID == id.Value).ToList();
            aViewModel.Vendor = db.Cs.Where(x => x.cID == aViewModel.a.cID).FirstOrDefault();

            return View(aViewModel);
        }

[HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(AViewModel aViewModel)
        {
            if (!canUserAccessA(aViewModel.a.aID) || aViewModel.a.UserID != WebSecurity.GetUserId(User.Identity.Name))
                return new HttpStatusCodeResult(HttpStatusCode.Forbidden);

            if (ModelState.IsValid)
            {
                db.Entry(aViewModel.a).State = EntityState.Modified; //THIS IS WHERE THE ERROR IS BEING THROWN
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(aViewModel);
        }

As shown above line

db.Entry(aViewModel.a).State = EntityState.Modified;

throws exception:

Attaching an entity of type 'A' 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.

Does anybody see anything wrong in my code or understand in what circumstances it would throw such error during editing a model?

This question is related to c# asp.net-mvc entity-framework

The answer is


Similar to what Luke Puplett is saying, the problem can be caused by not properly disposing or creating your context.

In my case, I had a class which accepted a context called ContextService:

public class ContextService : IDisposable
{
    private Context _context;

    public void Dispose()
    {
        _context.Dispose();
    }
    public ContextService(Context context)
    {
        _context = context;
    }
//... do stuff with the context

My context service had a function which updates an entity using an instantiated entity object:

        public void UpdateEntity(MyEntity myEntity, ICollection<int> ids)
        {
            var item = _context.Entry(myEntity);
            item.State = EntityState.Modified;
            item.Collection(x => x.RelatedEntities).Load();
            myEntity.RelatedEntities.Clear();
            foreach (var id in ids)
            {
                myEntity.RelatedEntities.Add(_context.RelatedEntities.Find(id));
            }
            _context.SaveChanges();
        }

All of this was fine, my controller where I initialized the service was the problem. My controller originally looked like this:

    private static NotificationService _service = 
        new NotificationService(new NotificationContext());
    public void Dispose()
    {
    }

I changed it to this and the error went away:

    private static NotificationService _service;
    public TemplateController()
    {
        _service = new NotificationService(new NotificationContext());
    }
    public void Dispose()
    {
        _service.Dispose();
    }

Clear all State

dbContextGlobalERP.ChangeTracker.Entries().Where(e => e.Entity != null).ToList().ForEach(e => e.State = EntityState.Detached);


I solve this problem with a "using" block

using (SqlConnection conn = new SqlConnection(connectionString))

    {

       // stuff to do with data base
    }

    // or if you are using entity framework 
    using (DataBaseEntity data = new DataBaseEntity)
{

    }

Here is where I get the idea https://social.msdn.microsoft.com/Forums/sqlserver/es-ES/b4b350ba-b0d5-464d-8656-8c117d55b2af/problema-al-modificar-en-entity-framework?forum=vcses is in spanish (look for the second answer)


I had a similar issue, after probing for 2-3 days found ".AsNoTracking" should be removed as EF doesn't track the changes and assumes there are no changes unless an object is attached. Also if we don't use .AsNoTracking, EF automatically knows which object to save/update so there is no need to use Attach/Added.


In my case , I had wrote really two times an entity of same type . So I delete it and all things work correctly


i mange to fix the issue by updating state. when you trigger find or any other query operation on the same record sate has been updated with modified so we need to set status to Detached then you can fire your update change

     ActivityEntity activity = new ActivityEntity();
      activity.name="vv";
    activity.ID = 22 ; //sample id
   var savedActivity = context.Activities.Find(22);

            if (savedActivity!=null)
            {
                context.Entry(savedActivity).State = EntityState.Detached;
                context.SaveChanges();

                activity.age= savedActivity.age;
                activity.marks= savedActivity.marks; 

                context.Entry(activity).State = EntityState.Modified;
                context.SaveChanges();
                return activity.ID;
            }

This problem may also be seen during ViewModel to EntityModel mapping (by using AutoMapper, etc.) and trying to include context.Entry().State and context.SaveChanges() such a using block as shown below would solve the problem. Please keep in mind that context.SaveChanges() method is used two times instead of using just after if-block as it must be in using block also.

public void Save(YourEntity entity)
{
    if (entity.Id == 0)
    {
        context.YourEntity.Add(entity);
        context.SaveChanges();
    }
    else
    {
        using (var context = new YourDbContext())
        {
            context.Entry(entity).State = EntityState.Modified;
            context.SaveChanges(); //Must be in using block
        }
    }            
}

Hope this helps...


My case was that I did not have direct access to EF context from my MVC app.

So if you are using some kind of repository for entity persistence it could be appropiate to simply detach explicitly loaded entity and then set binded EntityState to Modified.

Sample (abstract) code:

MVC

public ActionResult(A a)
{
  A aa = repo.Find(...);
  // some logic
  repo.Detach(aa);
  repo.Update(a);
}

Repository

void Update(A a)
{
   context.Entry(a).EntityState = EntityState.Modified;
   context.SaveChanges();
}

void Detach(A a)
{
   context.Entry(a).EntityState = EntityState.Detached;
}

I thought I'd share my experience on this one, even though I feel a bit silly for not realising sooner.

I am using the repository pattern with the repo instances injected into my controllers. The concrete repositories instantiate my ModelContext (DbContext) which lasts the lifetime of the repository, which is IDisposable and disposed by the controller.

The issue for me was that I have a modified stamp and row version on my entities, so I was getting them first in order to compare with the inbound headers. Of course, this loaded and tracked the entity that was subsequently being updated.

The fix was simply to change the repository from newing-up a context once in the constructor to having the following methods:

    private DbContext GetDbContext()
    {
        return this.GetDbContext(false);
    }


    protected virtual DbContext GetDbContext(bool canUseCachedContext)
    {
        if (_dbContext != null)
        {
            if (canUseCachedContext)
            {
                return _dbContext;
            }
            else
            {
                _dbContext.Dispose();
            }
        }

        _dbContext = new ModelContext();

        return _dbContext;
    }

    #region IDisposable Members

    public void Dispose()
    {
        this.Dispose(true);
    }

    protected virtual void Dispose(bool isDisposing)
    {
        if (!_isDisposed)
        {
            if (isDisposing)
            {
                // Clear down managed resources.

                if (_dbContext != null)
                    _dbContext.Dispose();
            }

            _isDisposed = true;
        }
    }

    #endregion

This allows the repository methods to re-new their context instance upon each use by calling GetDbContext, or use a previous instance if they so desire by specifying true.


Use AsNoTracking() where you are getting your query.

  var result = dbcontext.YourModel.AsNoTracking().Where(x => x.aID == aID && x.UserID==userID).Count();

Reasons I've encountered this error:

  1. Did not use .AsNoTracking() when querying for existing entities. Especially when calling a helper function to check permissions.
  2. Calling .Include() on a query and then trying to edit the parent. Example: var ent = repo.Query<Ent>().Include(e=>e.Ent2).First(); ...repo.Edit(e.Ent2); repo.Edit(e); If I'm going to edit a nested object, I try to separate these into separate query calls now. If you can't do that, set the child object to null and iterate through lists, detaching objects like this
  3. Editing an old entity in a Put web call. The new item is already added to the repo, so modify that one and have it be saved in super.Put(). Example of what will throw an error: public void Put(key, newItem){ var old = repo.Query<Entity>().Where(e=>Id==key).First(); ... repo.Edit(old); super.Put(key,newItem); ... }
  4. Multiple helper functions edit the same entity. Instead of passing the ID as a parameter into each function, pass a reference to the entity. Error solved!

Interestingly:

_dbContext.Set<T>().AddOrUpdate(entityToBeUpdatedWithId);

Or if you still is not generic:

_dbContext.Set<UserEntity>().AddOrUpdate(entityToBeUpdatedWithId);

seems to solved my problem smoothly.


Here what I did in the similar case.

That sitatuation means that same entity has already been existed in the context.So following can help

First check from ChangeTracker if the entity is in the context

var trackedEntries=GetContext().ChangeTracker.Entries<YourEntityType>().ToList();

var isAlreadyTracked =
                    trackedEntries.Any(trackedItem => trackedItem.Entity.Id ==myEntityToSave.Id);

If it exists

  if (isAlreadyTracked)
            {
                myEntityToSave= trackedEntries.First(trackedItem => trackedItem.Entity.Id == myEntityToSave.Id).Entity;
            } 

else
{
//Attach or Modify depending on your needs
}

I encountered this error where

  • two methods, A & B, in a single controller both used the same instance of an ApplicationDbContext, and
  • method A called method B
    private ApplicationDbContext db;
    // api methods
    public JsonResult methodA(string id){
        Resource resource = db.Resources.Find(id);
        db.Entry(resource).State = EntityState.Modified;
        db.SaveChanges();
        return methodB()
    }

    public JsonResult methodB(string id){
        Resource resource = db.Resources.Find(id);
        db.Entry(resource).State = EntityState.Modified;
        db.SaveChanges();
        return new JsonResult();
    }

I changed method B to have a using statement and rely only on the local db2. After:

    private ApplicationDbContext db;    
    // api methods    
    public JsonResult methodA(string id){
        Resource resource = db.Resources.Find(id);
        db.Entry(resource).State = EntityState.Modified;
        db.SaveChanges();
        return methodB()
    }

    public JsonResult methodB(string id){
        using (var db2 = new ApplicationDbContext())
        {
            Resource resource = db2.Resources.Find(id);
            db2.Entry(resource).State = EntityState.Modified;
            db2.SaveChanges();
        }
        return new JsonResult();
    }

for me the local copy was the source of the problem. this solved it

var local = context.Set<Contact>().Local.FirstOrDefault(c => c.ContactId == contact.ContactId);
                if (local != null)
                {
                    context.Entry(local).State = EntityState.Detached;
                }

Try this:

var local = yourDbContext.Set<YourModel>()
                         .Local
                         .FirstOrDefault(f => f.Id == yourModel.Id);
if (local != null)
{
  yourDbContext.Entry(local).State = EntityState.Detached;
}
yourDbContext.Entry(applicationModel).State = EntityState.Modified;

It seems that entity you are trying to modify is not being tracked correctly and therefore is not recognized as edited, but added instead.

Instead of directly setting state, try to do the following:

//db.Entry(aViewModel.a).State = EntityState.Modified;
db.As.Attach(aViewModel.a); 
db.SaveChanges();

Also, I would like to warn you that your code contains potential security vulnerability. If you are using entity directly in your view model, then you risk that somebody could modify contents of entity by adding correctly named fields in submitted form. For example, if user added input box with name "A.FirstName" and the entity contained such field, then the value would be bound to viewmodel and saved to database even if the user would not be allowed to change that in normal operation of application.

Update:

To get over security vulnerability mentioned previously, you should never expose your domain model as your viewmodel but use separate viewmodel instead. Then your action would receive viewmodel which you could map back to domain model using some mapping tool like AutoMapper. This would keep you safe from user modifying sensitive data.

Here is extended explanation:

http://www.stevefenton.co.uk/Content/Blog/Date/201303/Blog/Why-You-Never-Expose-Your-Domain-Model-As-Your-MVC-Model/


you can use added method like;

_dbContext.Entry(modelclassname).State = EntityState.Added;

but in many case if you want to use more than one model at that time this won't work because entity is already attached to another entity. So, at that time you can use ADDOrUpdate Entity Migration method which simply migrates object from one to another and as a result you wouldn't get any error.

_dbContext.Set<modelclassname>().AddOrUpdate(yourmodel);

I have added this answer only because the problem is explained based on more complex data pattern and I found it hard to understand here.

I created a fairly simple application. This error occurred inside Edit POST action. The action accepted ViewModel as an input parameter. The reason for using the ViewModel was to make some calculation before the record was saved.

Once the action passed through validation such as if(ModelState.IsValid), my wrongdoing was to project values from ViewModel into a completely new instance of Entity. I thought I'd have to create a new instance to store updated data and then saved such instance.

What I had realised later was that I had to read the record from database:

Student student = db.Students.Find(s => s.StudentID == ViewModel.StudentID);

and updated this object. Everything works now.


I had this problem with local var and i just detach it like this:

if (ModelState.IsValid)
{
    var old = db.Channel.Find(channel.Id);
    if (Request.Files.Count > 0)
    {
        HttpPostedFileBase objFiles = Request.Files[0];
        using (var binaryReader = new BinaryReader(objFiles.InputStream))
        {
            channel.GateImage = binaryReader.ReadBytes(objFiles.ContentLength);
        }

    }
    else
        channel.GateImage = old.GateImage;
    var cat = db.Category.Find(CatID);
    if (cat != null)
        channel.Category = cat;
    db.Entry(old).State = EntityState.Detached; // just added this line
    db.Entry(channel).State = EntityState.Modified;
    await db.SaveChangesAsync();
    return RedirectToAction("Index");
}
return View(channel);

Problem causes of loaded objects with same Key, so first we will detach that object and do the the updating to avoid conflict between two object with the same Key


Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to asp.net-mvc

Using Lato fonts in my css (@font-face) Better solution without exluding fields from Binding Vue.js get selected option on @change You must add a reference to assembly 'netstandard, Version=2.0.0.0 How to send json data in POST request using C# VS 2017 Metadata file '.dll could not be found The default XML namespace of the project must be the MSBuild XML namespace How to create roles in ASP.NET Core and assign them to users? The model item passed into the dictionary is of type .. but this dictionary requires a model item of type How to use npm with ASP.NET Core

Examples related to entity-framework

Entity Framework Core: A second operation started on this context before a previous operation completed EF Core add-migration Build Failed Entity Framework Core add unique constraint code-first 'No database provider has been configured for this DbContext' on SignInManager.PasswordSignInAsync The instance of entity type cannot be tracked because another instance of this type with the same key is already being tracked Auto-increment on partial primary key with Entity Framework Core Working with SQL views in Entity Framework Core How can I make my string property nullable? Lazy Loading vs Eager Loading How to add/update child entities when updating a parent entity in EF