Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The instance of entity type cannot be tracked because another instance of this type with the same key is already being tracked

I have a Service Object Update

public bool Update(object original, object modified) {     var originalClient = (Client)original;     var modifiedClient = (Client)modified;     _context.Clients.Update(originalClient); //<-- throws the error     _context.SaveChanges();     //Variance checking and logging of changes between the modified and original } 

This is where I am calling this method from:

public IActionResult Update(DetailViewModel vm) {     var originalClient = (Client)_service.GetAsNoTracking(vm.ClientId);     var modifiedClient = (Client)_service.Fetch(vm.ClientId.ToString());     // Changing the modifiedClient here     _service.Update(originalClient, modifiedClient); } 

Here is the GetAsNotTracking method:

public Client GetAsNoTracking(long id) {     return GetClientQueryableObject(id).AsNoTracking().FirstOrDefault(); } 

Fetch method:

public object Fetch(string id) {    long fetchId;    long.TryParse(id, out fetchId);    return GetClientQueryableObject(fetchId).FirstOrDefault(); } 

GetClientQueryableObject:

private Microsoft.Data.Entity.Query.IIncludableQueryable<Client, ActivityType> GetClientQueryableObject(long searchId) {     return _context.Clients         .Where(x => x.Id == searchId)         .Include(x => x.Opportunities)         .ThenInclude(x => x.BusinessUnit)         .Include(x => x.Opportunities)         .ThenInclude(x => x.Probability)         .Include(x => x.Industry)         .Include(x => x.Activities)         .ThenInclude(x => x.User)         .Include(x => x.Activities)         .ThenInclude(x => x.ActivityType);  } 

Any ideas?

I have looked the following articles / discussions. To no avail:ASP.NET GitHub Issue 3839

UPDATE:

Here are the changes to GetAsNoTracking:

public Client GetAsNoTracking(long id) {     return GetClientQueryableObjectAsNoTracking(id).FirstOrDefault(); } 

GetClientQueryableObjectAsNoTracking:

private IQueryable<Client> GetClientQueryableObjectAsNoTracking(long searchId) {     return _context.Clients         .Where(x => x.Id == searchId)         .Include(x => x.Opportunities)         .ThenInclude(x => x.BusinessUnit)         .AsNoTracking()         .Include(x => x.Opportunities)         .ThenInclude(x => x.Probability)         .AsNoTracking()         .Include(x => x.Industry)         .AsNoTracking()         .Include(x => x.Activities)         .ThenInclude(x => x.User)         .AsNoTracking()         .Include(x => x.Activities)         .ThenInclude(x => x.ActivityType)         .AsNoTracking(); } 
like image 739
Rijnhardt Avatar asked Apr 26 '16 05:04

Rijnhardt


People also ask

Is already being tracked when attaching existing entities ensure that only one entity instance with?

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.

What is AsNoTracking in entity Framework?

AsNoTracking(IQueryable)Returns a new query where the entities returned will not be cached in the DbContext or ObjectContext. This method works by calling the AsNoTracking method of the underlying query object.


2 Answers

Without overriding EF track system, you can also Detach the 'local' entry and attach your updated entry before saving :

//  var local = _context.Set<YourEntity>()     .Local     .FirstOrDefault(entry => entry.Id.Equals(entryId));  // check if local is not null  if (local != null) {     // detach     _context.Entry(local).State = EntityState.Detached; } // set Modified flag in your entry _context.Entry(entryToUpdate).State = EntityState.Modified;  // save  _context.SaveChanges(); 

UPDATE: To avoid code redundancy, you can do an extension method :

public static void DetachLocal<T>(this DbContext context, T t, string entryId)      where T : class, IIdentifier  {     var local = context.Set<T>()         .Local         .FirstOrDefault(entry => entry.Id.Equals(entryId));     if (!local.IsNull())     {         context.Entry(local).State = EntityState.Detached;     }     context.Entry(t).State = EntityState.Modified; } 

My IIdentifier interface has just an Id string property.

Whatever your Entity, you can use this method on your context :

_context.DetachLocal(tmodel, id); _context.SaveChanges(); 
like image 90
Andres Talavera Avatar answered Sep 19 '22 23:09

Andres Talavera


public async Task<Product> GetValue(int id)     {         Product Products = await _context.Products.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id);         return Products;     } 

AsNoTracking()

like image 34
SHUBHASIS MAHATA Avatar answered Sep 23 '22 23:09

SHUBHASIS MAHATA