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.
```c#
// db init
public static StoreContext ConfigureStoreContext(IServiceCollection services, ITestOutputHelper output)
{
services.AddDbContext
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.IdentityMap1.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
```
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
```C#
public TestBase()
{
services = new ServiceCollection();
storeContext = StoreContextMock.ConfigureStoreContext(services, output);
serviceProvider = services.BuildServiceProvider();
}
public static StoreContext ConfigureStoreContext(IServiceCollection services)
{
services.AddDbContext
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 = "[email protected]" });
storeContext .Stores.Add(new Store { Title = "Jennifer's store", Address = "Sydney", Description = "Fashion", SellerId = "[email protected]" });
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.
```C#
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 = "[email protected]" };
var s2 = new Store { Title = "Jennifer's store", Address = "Sydney", Description = "Fashion", SellerId = "[email protected]" }
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,
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.'
@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.
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
@pballewsa I set Id because I wanted to update entity, not create one. I've found solution, check it above.
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
@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.
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
DbContextInMemory.Entry
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;
}
Using NoTracking before using context.
{YourContext}.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
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.
I also having the same issue and tried all the mentioned above approach but still stuck on the same issue.Any help will be highly appropriated.
//_databaseContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var allItems = await _databaseContext.DbRefData.AsNoTracking().LastOrDefaultAsync().ConfigureAwait(false);
//_databaseContext.Entry(item).State = EntityState.Detached;
if (allItems == null)
{
await _databaseContext.DbRefData.AddAsync(item).ConfigureAwait(false);
await _databaseContext.SaveChangesAsync().ConfigureAwait(false);
}
else
{
item.Id = allItems.Id;
_databaseContext.DbRefData.Update(item);
await _databaseContext.SaveChangesAsync().ConfigureAwait(false);
}
Hi,
I've runned into same error with empty database when I've tried to add 5000 elements in single SaveChanges
When I splited it to 50 batches everything works, so there must be some error in NET Core itself
THIS CODE DO NOT WORK
public void AddInstances(List<CardInstance> cardInstances)
{
context.PlayersCards.AddRange(cardInstances);
context.SaveChanges();
}
THIS CODE WORKS
public static List<List<T>> splitList<T>(List<T> locations, int nSize = 30)
{
var list = new List<List<T>>();
for (int i = 0; i < locations.Count; i += nSize)
{
list.Add(locations.GetRange(i, Math.Min(nSize, locations.Count - i)));
}
return list;
}
public void AddInstances(List<CardInstance> cardInstances)
{
cardInstances = cardInstances.Except(context.PlayersCards).ToList();
var batches = CardRepository.splitList(cardInstances, 100);
batches.ForEach(x =>
{
context.PlayersCards.AddRange(x);
context.SaveChanges();
});
}
@titscrypto Please open a new issue and include a small, runnable project/solution or complete code listing that demonstrates the behavior you are seeing.
Why was this issue closed? I am seeing the same behavior.
@aaronhudon The issue is closed because on further investigation none of the reported situations are product bugs. If you're seeing something that you think is a product bug, then please open a new issue and provide a small, runnable project/solution of complete code listing that demonstrates the bug so that we can investigate.
@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.
we solved the issue by calling the DBcontext call in using block for all the DBcall.
```cs
storeContext.Stores.Add(s1);
storeContext.Stores.Add(s2);
storeContext.Entry(s1).State = EntityState.Detached;
storeContext.Entry(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 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.
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:
hope this help.
https://github.com/aspnet/EntityFrameworkCore/issues/12459#issuecomment-399994558
That is one of many reasons why dbContext should be limited by a scope.
Thanks for the hint.
Thanks it worked !
I spent a lot of time to solve this and applied all soln at net but only this resolve my issue and made all test cases pass successfully while running all in one go.
Just use the DBContext within the using block. dbContext should be limited by a scope otherwise it will throw this kind of issue
public async Task<LogItem> GetLogItemAsync(int id)
{
using (dbContext = new DatabaseContext(dbConnection))
{
return await dbContext.DbLog.FirstOrDefaultAsync(x => x.AutoId == id).ConfigureAwait(false);
}
}
I had this error message appear when I was trying to write to a MS-SQL database in a background task (dot-net core 3.1) and inadvertently tried to write a record with the same primary key to the database.
Instead of "primary key violation" that I would normally expect, I got this error (I think) BECAUSE the thread was running as a background task. Once I fixed the bug that was causing the attempted duplicate insert of a primary key, the error went away.
Hi,
in my case the problem was that I created a new entity instead of update the original one on updating.Changing:
request.prop1 = new request().prop1 TO
request.prop1 = requestDTO.prop1 solved the problem!
Hi i have this problem too
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.'
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.
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 have the same problem, i have a generic repository and facing the issue in the only update case, the code is given below
please help me to solve the issue
`
public async Task<T> Update(T entity)
{
if (entity == null)
{
throw new ArgumentException("model");
}
entity.Updated = DateTimeOffset.UtcNow;
try
{
this.coreContext.Entry(entity).State = EntityState.Modified;
await this.coreContext.SaveChangesAsync();
}
catch (Exception ex)
{
// Todo: replace with Microsoft.Extensions.Logger
Console.WriteLine(ex.ToString());
throw ex;
}
return entity;
}
}`
Have you set your dbContext to Notracking Behaviour. Something like this
DbContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
yes i am doing when at the application startup
code is given below
services.AddDbContext<CoreContext>(
opt => opt.UseSqlServer($"{Program.Configuration["sqlConnectionString"]}", o => o.CommandTimeout(180))
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking), ServiceLifetime.Transient);
what's the point of using EF if, instead of writing queries, you have to write additional code to avoid such bollocks ??
I got this error from my background service. I solved which creating a new scope.
using (var scope = serviceProvider.CreateScope())
{
// Process
}
I am using UpdateRange method multiple times on same type of dbset, for saving nontracked entities,
fetched using AsNoTracking() and also have disabled QueryTrackingBehaviour before using context,
I am updatting dbset initially updating one column and after other application logic operations,
I fetch same dbset AsNoTracking() and I update other two columns.
For first call to UpdateRange and SaveChanges it was working fine
after few methods call not related to ef core but application logic
I am fetching again nontracked entities for same dbset type and try to save
this time UpdateRange method throws error EF Core 'another instance is already being tracked'
Is this behaviour correct?
I feel currently this is incorrect
If i am fetching again nontracked entities for dbset modify and then call UpdateRange it should work
I am able to workaround currently by marking entities detached with looping over entities i used in updatedrange call and after savechanges I detach
I feel updaterange behaviour is correct if we have tracking behaviour, can we have another overload for nontracking where in updaterange after save entites will be marked detached
@rameshbsupekar cross-posted as #23581, hiding.
dec 2020 - I had to disabled change query tracking form the from the dbContext , this is what worked for me :
services.AddDbContext
{
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
});
Most helpful comment
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
```C#(c =>
public TestBase()
{
services = new ServiceCollection();
storeContext = StoreContextMock.ConfigureStoreContext(services, output);
serviceProvider = services.BuildServiceProvider();
}
public static StoreContext ConfigureStoreContext(IServiceCollection services)
{
services.AddDbContext
c.UseInMemoryDatabase(Guid.NewGuid().ToString()).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking));
That is one of many reasons why dbContext should be limited by a scope.
Thanks for the hint.