I am creating an API using ASP.NET5 and Entity Framework 7.0.0-beta 6, and when I try to execute various updates in several requests, I get this Exception:
_'Company' cannot be tracked because another instance of this type with the same key is already being tracked. For new entities consider using an IIdentityGenerator to generate unique key values._
This is my code:
public class MrBellhopContext : DbContext
{
public DbSet<Company> Company { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Company>(entity =>
{
entity.Key(c => c.CompanyId);
entity.Index(c => c.Name);
entity.Property(c => c.CompanyId).ValueGeneratedOnAdd();
});
modelBuilder.UseSqlServerIdentityColumns();
base.OnModelCreating(modelBuilder);
}
}
public class Company
{
public int CompanyId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public short StatusId { get; set; }
}
public class CompanyRepository : ICompanyRepository
{
MrBellhopContext _dbcontext;
public async Task UpdateAsync(Company company)
{
_dbcontext.Update(company);
await _dbcontext.SaveChangesAsync();
}
}
[Route("api/[controller]")]
public class CompanyController : Controller
{
[HttpPut]
public async void UpdateAsync([FromBody] Company company)
{
if ((!ModelState.IsValid) || (company == null))
{
Context.Response.StatusCode = 400;
return;
}
else
{
await _repository.UpdateAsync(company);
}
}
}
I have tried to solve it by removing ValueGeneratedOnAdd(), UseSqlServerIdentityColumns() or changing the mapping, but if I try to update several entities in several requests, I get the Exception:
First req: Update CompanyId 8
First req: Update CompanyId 9 !! ERROR
Does anyone know how to solve this issue?
@unairoldan could it be that you are trying to use the same context instance to update two different instances of an entity that have the same key?
There isn't a lot we can do here without a full set of code to reproduce the issue. Any chance you could share a project? The full stack trace from the exception would be useful too.
This is the full stack trace:
An exception of type 'System.InvalidOperationException' occurred in mscorlib.dll but was not handled in user code
Additional information: The instance of entity type 'MrBellhop.Model.Company.Company' cannot be tracked because another instance of this type with the same key is already being tracked. For new entities consider using an IIdentityGenerator to generate unique key values.
at Microsoft.Data.Entity.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
at Microsoft.Data.Entity.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges)
at Microsoft.Data.Entity.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges)
at Microsoft.Data.Entity.ChangeTracking.EntityEntry.set_State(EntityState value)
at Microsoft.Data.Entity.DbContext.SetEntityState[TEntity](TEntity entity, EntityState entityState)
at Microsoft.Data.Entity.DbContext.Update[TEntity](TEntity entity)
at MrBellhop.Data.Repositories.Company.CompanyRepository.<UpdateAsync>d__5.MoveNext() in D:\SciOf\MrBellhop\MrBellhop.Data\Repositories\Company\CompanyRepository.cs:line 46
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at MrBellhop.API.Controllers.Company.CompanyController.<UpdateAsync>d__9.MoveNext() in D:\SciOf\MrBellhop\MrBellhop.API\Controllers\Company\CompanyController.cs:line 62
I have shared the example project in this repository:
https://github.com/unairoldan/EF7-beta-6-MS_Example/tree/553ccd7b5724fec21d62aa1785da2161a32ae2c2
I just delete some code (from other DB entities) to make easier track the problem
@unairoldan that exception means that you are trying to attach two entity instances that have the same key to a context. This isn't supported in EF. There can only be one entity instance with a given key per context.
This is occurring because you have added a singleton instance of your repository:
services.AddSingleton<Data.Interfaces.Company.ICompanyRepository,Data.Repositories.Company.CompanyRepository>();
This means that all requests are sharing a single instance of the repository. You should reduce this to Scoped, so that you have a single repository instance per request. Aside from avoiding the issue you are hitting, it will also ensure you don't end up with a gigantic context instance tracking all the data from your database in memory.
Hi I am using single ton Database context. I am getting the same error as above.
The instance of entity type 'Person' cannot be tracked because another instance of this type with the same key is already being tracked
Please suggest.
Single ton Database Context but scoped repositories.
@gollapudiramyak we do not recommend using a singleton context. This is especially true if you are in a web application since DbContext is not thread safe and you will get undefined behavior if you try to use the same context from two threads (which is what you'll get when you have two concurrent web requests).
As you discovered, if you share a context between parts of the application, you also need to deal with ensuring that you only have one instance that represents a given entity. That is one of the reasons we recommend having short lived context instances.
Thank you for your quick reply.
How about using .AsNoTracking for all Get operations. like below
``` c#
context.User..AsNoTracking()
//To Get the User
MyDataBaseContext.context.Attach(userobject);
MyDataBaseContext.context.SaveChanges();
// To Update the User
MyDataBaseContext.context.User.Add(userobject );
DatabaseContext.context.SaveChanges();
//To Insert a new User
Reason for going for single ton datacontext is - don't want to open the connection for each operation from entities. Example like below for 2 entities. We have about 90 entities which are there in my MyDbontext.
``` c#
using(MyDbContext db= new MyDbContext(connectionString))//open connecion
{
return db.Users;
}//closes connection
using(MyDbContext db= new MyDbContext(connectionString))//open connecion
{
return db.Person;
}//closes connection
Singleton generally means one context instance per AppDomain, that is something you should avoid. If you want to use the same context instance for a series of operations then that is fine (i.e. open connection and run two queries)... just be careful that it is not used on two different threads.
BTW I'd be careful not to prematurely optimize things... often times folks end up building something really complex and it ends up being way slower than just letting EF open and close connections etc. as it normally would.
Thank you. If we use short lived context objects overserved the below highlighted ones
``` c#
public IEnumerable
{
using (BloggingContext db = new BloggingContext())
{
var list= db.orgs.ToList(); *//Its calling OnConfiguration Method of Blogging Context
* }
using (BloggingContext db = new BloggingContext())
{
return db.orgs.ToList();** //Its calling OnConfiguration Method of Blogging Context
**
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.Options.Extensions.Any())
{
optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString); **//This Line is called twice in this example - i.e each time I call db.orgs.ToList().**
}
}
```
How the Connection management and connection pooling is maintained by entity framework? Will this be ok the onconfigurationmethod called multiple times from the application which has loads of call to entities.
OnConfiguring is called each time you construct a context. We don't do any caching here because it's "cheap" code to run - all it's doing to stashing a few values away for the context. Connection pooling is handled by ADO.NET (SQL Client, if you are targeting SQL Server).
I would really only start mucking around with connections etc. if you have a particular part of the application where you are seeing poor performance and the problem can be addressed by re-using the same DbConnection. For the most part, I think you are going too get the best perf if you just let ADO.NET take care of connection pooling for you and use short lived contexts that will open and close the connection as needed.
Before update data we have fetch existing data row from data base like that
_context.TableName.SingleOrDefault(p => p.Id ==id);
so we need to use AsNoTracking when fetch data
_context.TableName.AsNoTracking().SingleOrDefault(p => p.Id ==id);
and for Updata data in database use
_context.TableName.Update(updatingTableEntity);
I have a similar issue: I have two classes: JournalEntry, and JournalEntryItem (references JournalEntry). I do not want EF to operate on my classes as a graph, but rather singular individual entities.
In the example below I'm addressing a list of three objects (JournalEntry, JournalEntryItem,JournalEntryItem). On the third iteration of my loop I'm adding JournalEntryItem to the dbcontext and it complains that JournalEntry is already in there. It appears as if Entry() is reading the entire object graph.
The problem line is:
this.DbContext.Entry(dbDataModel).State = EntityStates.Modified; on the third iteration...dbDataModel in this case is a JournalEntryItem, but it throws an error saying JournalEntry is already being tracked.
Without debugging

With debugging

@BlackjacketMack you can only have one instance of an entity with the same key values being tracked by the same context instance.. so it seems that there must be two JournalEntrys with the same key. If this is intentional, then perhaps use a fresh context instance for each iteration of the loop?
@rowanmiller What I ended up doing was calling SaveChanges() and detaching the object for each iteration. It works, but I don't get the nicely bundled inserts. That's ok! Thanks for your help.
@BlackjacketMack I am having the same problem. How did you manage that?
For what it's worth, I've just spent hours debugging this issue.
Turns out I _was_ actually tracking two copies of the same entity. Go figure..
@fergalmoran if you are hitting an issue similar to the one originally posted here using a non-preview version of EF Core, could you please create a new issue and provide a repro?
Hi @divega, sorry I wasn't clearer. What I meant was that I hit this issue and the problem turned out to be EXACTLY what the error message was telling me it was, it just took me hours to realise that..
Most helpful comment
@unairoldan that exception means that you are trying to attach two entity instances that have the same key to a context. This isn't supported in EF. There can only be one entity instance with a given key per context.
This is occurring because you have added a singleton instance of your repository:
This means that all requests are sharing a single instance of the repository. You should reduce this to Scoped, so that you have a single repository instance per request. Aside from avoiding the issue you are hitting, it will also ensure you don't end up with a gigantic context instance tracking all the data from your database in memory.