efcore: The instance of entity type cannot be tracked because another instance with the same key value for {'Id'} is already being tracked

I am aware that such question has already been asked numerous times, but solutions did not help me. I try to unit test my code in XUnit, but have numerous issues with EF Core, here is one of them.

// db init
public static StoreContext ConfigureStoreContext(IServiceCollection services, ITestOutputHelper output)
{
        services.AddDbContext<StoreContext>(c =>
            c.UseInMemoryDatabase(Guid.NewGuid().ToString()));

        var serviceProvider = services.BuildServiceProvider();
        var context = serviceProvider.GetRequiredService<StoreContext>();
        StoreContextSeed.SeedStoreAsync(context);
        return context;
}

[Fact]
public async Task UpdateAsync()
{
    string newTitle = "newTitle1";
    int newBrandId = 3;
    //var item = await storeContext.Items.AsNoTracking().FirstOrDefaultAsync(); // result is the same
    var item = new Item()
    {
        Id = 1,
        BrandId = newBrandId,
        CategoryId = 1,
        MeasurementUnitId = 1,
        StoreId = 1,
        Title = newTitle
    };
    storeContext.Entry(item).State = EntityState.Detached; // has no effect, could be removed. 
    //if assign Deleted, then get error "can not update deleted item"
    await service.UpdateAsync(item); // exception inside
    var updatedItem = await storeContext.Items.AsNoTracking().FirstOrDefaultAsync();
    Assert.Equal(newTitle, updatedItem.Title);
    Assert.Equal(newBrandId, updatedItem.BrandId);
}

public async Task UpdateAsync(T entity)
{
    _dbContext.Entry(entity).State = EntityState.Modified; // exception when trying to change the state
    await _dbContext.SaveChangesAsync();
}

Further technical details

EF Core version: 2.1 Database Provider: InMemory Operating system: IDE: (Visual Studio 2017 15.7)

Test Name:	UnitTests.Services.StoreServiceTests.UpdateAsync
Test FullName:	UnitTests.Services.StoreServiceTests.UpdateAsync
Test Source:	C:\Users\kozachenkoav\source\repos\OctopusStore\UnitTests\Services\StoreServiceTests.cs : line 56
Test Outcome:	Failed
Test Duration:	0:00:02,242

Result StackTrace:	
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges)
   at Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry.set_State(EntityState value)
   at Infrastructure.Data.EfRepository`1.UpdateAsync(T entity) in C:\Users\kozachenkoav\source\repos\OctopusStore\Infrastructure\Data\EfRepository.cs:line 54
   at Infrastructure.Services.StoreService.UpdateAsync(Store store) in C:\Users\kozachenkoav\source\repos\OctopusStore\Infrastructure\Services\StoreService.cs:line 29
   at UnitTests.Services.StoreServiceTests.UpdateAsync() in C:\Users\kozachenkoav\source\repos\OctopusStore\UnitTests\Services\StoreServiceTests.cs:line 71
--- End of stack trace from previous location where exception was thrown ---
Result Message:	System.InvalidOperationException : The instance of entity type 'Store' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 52
  • Comments: 41 (3 by maintainers)

Most upvoted comments

what’s the point of using EF if, instead of writing queries, you have to write additional code to avoid such bollocks ??

Numerous issues I’ve been running into have one nasty root. In a nutshell: I’ve learned the hard way why dbContext is scoped rather than singleton. Here is Store type, but the issue was the same. Here is simplified test initialization code

    public TestBase()
    {
        services = new ServiceCollection();
        storeContext = StoreContextMock.ConfigureStoreContext(services, output);
        serviceProvider = services.BuildServiceProvider();
    }
    public static StoreContext ConfigureStoreContext(IServiceCollection services)
    {
        services.AddDbContext<StoreContext>(c =>
            c.UseInMemoryDatabase(Guid.NewGuid().ToString()).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking));

        var serviceProvider = services.BuildServiceProvider();
        var storeContext = serviceProvider.GetRequiredService<StoreContext>();
        storeContext .Stores.Add(new Store { Title = "John's store", Address = "NY", Description = "Electronics best deals", SellerId = "john@mail.com" });
        storeContext .Stores.Add(new Store { Title = "Jennifer's store", Address = "Sydney", Description = "Fashion", SellerId = "jennifer@mail.com" });
        storeContext .SaveChanges();
        return storeContext ;
    }

I reread error and finally noticed the main word

The instance of entity type ‘Store’ cannot be tracked because another instance with the same key value for {‘Id’} is already being tracked

So there has to be some orphan tracked instance preventing me from working with store. I did not save any references to s1 or s2, so it must be storeContext storing references on inserted objects even after leaving scope of their declaration and initialization. That’s why I was unable update variables normally and also why my ‘queried’ from db objects had all their navigation properties assigned (lazy loading has little to do with this). The following code resolved all my issues.

    public static StoreContext ConfigureStoreContext(IServiceCollection services)
    {
        services.AddDbContext<StoreContext>(c =>
            c.UseInMemoryDatabase(Guid.NewGuid().ToString()).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking));

        var serviceProvider = services.BuildServiceProvider();
        var storeContext = serviceProvider.GetRequiredService<StoreContext>();
        var s1 = new Store { Title = "John's store", Address = "NY", Description = "Electronics best deals", SellerId = "john@mail.com" };
        var s2 = new Store { Title = "Jennifer's store", Address = "Sydney", Description = "Fashion", SellerId = "jennifer@mail.com" }
        storeContext.Stores.Add(s1);
        storeContext.Stores.Add(s2);
        storeContext.Entry<Store>(s1).State = EntityState.Detached;
        storeContext.Entry<Store>(s2).State = EntityState.Detached;
        storeContext.SaveChanges();
        return storeContext;
    }

That is one of many reasons why dbContext should be limited by a scope. Thanks for the hint.

Hi

Hi,

I am also having same issue. After i added the detach property its returns the error as Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: ‘Attempted to update or delete an entity that does not exist in the store.’

I have fixed this using the following code: var entity = await DbContextInMemory.FindAsync<EntityName>(EntityId); //To Avoid tracking error DbContextInMemory.Entry<EntityName>(entity).State = EntityState.Detached;

Hi

Hi, I am also having same issue. After i added the detach property its returns the error as Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: ‘Attempted to update or delete an entity that does not exist in the store.’

I have fixed this using the following code: var entity = await DbContextInMemory.FindAsync(EntityId); //To Avoid tracking error DbContextInMemory.Entry(entity).State = EntityState.Detached;

Thank you for the recommendation, @svipandi it works perfectly:

public Users GetUserByUserName(string userName, bool detachIt) {
	Users user = _context.Users.Include(u => u.AspnetUser).FirstOrDefault(u => u.AspnetUser.UserName == userName);
	if (detachIt) {
		// Deatch the user, so they can edit themself on an edit page, to avoid
		// The instance of entity type cannot be tracked because another instance with the same key value for {'...'} is already being tracked
		_context.Entry(user).State = EntityState.Detached;
	}
	return user;
}
storeContext.Stores.Add(s1);
        storeContext.Stores.Add(s2);
        storeContext.Entry<Store>(s1).State = EntityState.Detached;
        storeContext.Entry<Store>(s2).S

It works for me by this order,

1- context.Customers.Update/Add(customer); 2- context.SaveChanges();

3- context.Entry(customer).State = EntityState.Detached;

I noticed that you’re setting Item.Id when you create the object. Is that by any chance a database generated Id? If so, it may work to not set that value.

The same error comes up with in-memory DB unit tests anytime you try to do something like this:

public class Item
{
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public string Name { get; set; }
}
(in unit test)
var item = new Item() { Id = 0, Name = "My Item" };
context.Items.Add(item);
context.SaveChanges();

Hope that helps. Paul

@svipandi check carefully places where you created context instance. once you added object via context instance, tracking won’t stop (except when you explicitly detach the very same object you added) , so you have to limit the scope of your context instance.

dec 2020 - I had to disabled change query tracking form the from the dbContext , this is what worked for me :

services.AddDbContext<ApiDbContext>(options => { options.UseNpgsql(Configuration.GetConnectionString(“DefaultConnection”)).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); });

I am using EF Core 3.1 InMemory Database Provider. To resolve this issue I had to Detach Each Entry of the dbContext And Set DbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;.

The below code worked for me

 public IAsyncEnumerable<ScheduledJobModel> GetData()
        {
            var clients = SchedulerJobIntegrationTestFixture.CreateClientStub();
           
            InMemoryScheduleDbContext.Clients.AddRange(clients);
            InMemoryScheduleDbContext.SaveChanges();

            foreach (var entity in InMemoryScheduleDbContext.ChangeTracker.Entries())
            {
                entity.State = EntityState.Detached;
            }
            return QueueManager.QueryScheduledJobsWithActiveReminder();
        }

Hi,

// I used this part above. Category category = categoryService.GetById(categoryCreateDto.Id);

// I also received an error because I am rebuilding it. Category mappedCategory = mapper.Map<Category>(categoryCreateDto);

//Category mappedCategory = mapper.Map(categoryCreateDto, category); categoryService.Update(mappedCategory);

I have fixed this using the following code: I’ve edited here like this. Category mappedCategory = mapper.Map(categoryCreateDto, category);

I didn’t create another new category. I used the existing one.

@titscrypto Please open a new issue and include a small, runnable project/solution or complete code listing that demonstrates the behavior you are seeing.

I also had this issue using xUnit. I’m creating a DbContext with the UseInMemoryDatabase() option, adding some mock data, then injecting that context into the classes I’m testing.

What resolved the tracking errors was disposing the DbContext that I used to insert the mock data then injecting a new DbContext instance with the same options into the test code.

Update 2 months later: I got this again. This time the fix was change the IDs of mocked entities from 0-10 to 1-11.

Why was this issue closed? I am seeing the same behavior.

Using NoTracking before using context. {YourContext}.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

Hi all,

I have same issue.I develop generic repository with .net core 2.1.1 Web api. I used AddSingleton DbContext on DependencyInjection . Get,GetAll,Post,Delete is working. But Put(Update) is not working.Please give me advice.

Controller

   public async Task<IActionResult> PutCountry([FromRoute] int id, [FromBody] Country country)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        if (id != country.Id)
        {
            return BadRequest();
        }

        try
        {
            var hasCountry = await _countryService.FindByConditionAsync(_ => _.Id == id);

            if (hasCountry.FirstOrDefault() != null)//Update yapılacak bir data var mı?
            {

                try
                {
                    await _countryService.UpdateAsync(country);
                }
                catch (Exception ex)
                {
                    throw ex;
                }


            }
            else
            {
                return NotFound(country);
            }

        }
        catch (DbUpdateConcurrencyException)
        {
            var result = await _countryService.FindByConditionAsync(_ => _.Id == id);
            if (result.FirstOrDefault() != null)
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }

        return NoContent();

    }

Generic Repository UpdateAsync

    public void UpdateAsync(TEntity entity)
    {
 
        var updatedEntity = RepositoryContext.Set<TEntity>().Update(entity);//This line is goes to catch error block
        updatedEntity.State = EntityState.Modified;

    }

Edit:

I solved the issue.Closed the lazyLoading and after use asnotracking but I want to get relational models.How can I solve this?

Best Regards, Onur

Have you set your dbContext to Notracking Behaviour. Something like this DbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

I faced this issue when using UseInMemoryDatabase in xunit testing. my case was:

var product = productService.CreateProduct(...); // (1)
var updatedProduct = productService.UpdateProduct(product); // error here

the problem is after (1), product is “cached” in dbset Local property (see Local)

This local view will stay in sync as entities are added or removed from the context.

so in my generic repository, I added 1 more condition before update:

// repository.cs
public void Update(T entity)
{
  if (IsDetached(entity) // ⬅️ add this
    dbset.Attach(entity);

  //... the rest
  // context.Entry(entity).State = EntityState.Modified;
}

and my IsDetached method is:

private bool IsDetached(T entity)
{
  var localEntity = dbset.Local?.FirstOrDefault(x => Equals(x.Id, entity.Id));
  if (localEntity != null) // entity stored in local
    return false;

  return context.Entry(entity).State == EntityState.Detached;
}

notes:

  • dbset: DbSet<T>
  • context: ApplicationDbContext

hope this help.

@OnurSevket

I used AddSingleton DbContext on DependencyInjection

here is you problem, mate. DbContext instance won’t let any object go. if you’ve added (or retrieved without AsNoTracking()) object, it will keep reference to it (even if you don’t save it explicitly), therefore this object will always be tracked. Singleton DbContext doesn’t really make sense, I would recommend you to add DbOptions as a singleton like so DbContextOptions<DbContext> contextOptions = new DbContextOptionsBuilder<DbContext>().UseInMemoryDatabase("Context").Options; services.AddSingleton(contextOptions ); and DbContext as scoped. Hope this helps.

It’s better to Clear ChangeTracking After ContextSaveChanges.

_context.ChangeTracker.Clear();

This is case when you use InMemory database and this is why it is not a RDBMS so you should use SqlLite instead of InMemory . SqlLite is a RDBMS and I used it for unit Testing and working fine now.

@ajcvickers the issue cropped up for me when testing a local Azure function app. The function app instantiates an instance of a DbContext for each request. The error went away after restarting the function app. I’m concerned that even though the DbContext is created for each request, some internal bits are hanging around for the life of the app, not just the request.