dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.79k stars 3.19k forks source link

Additional information: The instance of entity type ... 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. #3839

Closed gilmaremn closed 2 years ago

gilmaremn commented 8 years ago

I have a generic repository implemented in a class library all CRUD methods except works _dbSet.Remove(entity);

The instance of the object is defined as AddScope.

Could someone help me

An exception of type 'System.InvalidOperationException' occurred in EntityFramework.Core.dll but was not handled in user code

Additional information: The instance of entity type 'TMS.Domain.Entities.Pais' 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.

public class RepositoryBase<TEntity> : IRepositoryBase<TEntity> where TEntity : class
{

    private IAppDbContext _dbContext;
    protected DbSet<TEntity> _dbSet;

    public RepositoryBase(IAppDbContext dbContext)
    {
        _dbContext = dbContext;
        _dbSet = _dbContext.Set<TEntity>();
    }

    //public RepositoryBase()
    //{
    //    _dbContext = new AppDbContext();
    //    _dbSet = _dbContext.Set<TEntity>();
    //}

    public virtual IEnumerable<TEntity> GetAll()
    {
        return _dbSet.ToList();
    }

    public IEnumerable<TEntity> GetAllAsReadOnly()
    {
        return _dbSet.AsNoTracking();
    }

    public virtual IEnumerable<TEntity> GetBy(Expression<Func<TEntity, bool>> filter)
    {
        return _dbSet.Where(filter);
    }

    public IQueryable<TEntity> GetQueryBy(Expression<Func<TEntity, bool>> filter)
    {
        return _dbSet.Where(filter);
    }

    public virtual void Create(TEntity entity)
    {
        _dbSet.Add(entity);
    }

    public virtual void Edit(TEntity entity)
    {
        _dbSet.Update(entity);
    }

    public virtual void Delete(TEntity entity)
    {
        _dbSet.Remove(entity);
    }

    public int Save()
    {
        return _dbContext.SaveChanges();
    }

    public void Dispose()
    {
        //_dbContext.Dispose();
        GC.SuppressFinalize(this);
    }

    public TEntity FindBy(Expression<Func<TEntity, bool>> filter)
    {
        return _dbSet.Where(filter).SingleOrDefault();
    }

    public TEntity FindAsReadOnlyBy(Expression<Func<TEntity, bool>> filter)
    {
        return _dbSet.Where(filter).AsNoTracking().SingleOrDefault();
    }

    public void Delete(Expression<Func<TEntity, bool>> filter)
    {
        TEntity entity = _dbSet.Where(filter).SingleOrDefault();
        _dbSet.Remove(entity);
    }
}
rowanmiller commented 8 years ago

as the error suggests, it sounds like your context instance already has an Addon with the same primary key value as one that you are trying to query/add/etc. Can you post the full stack trace?

gilmaremn commented 8 years ago

This is the stack:

InvalidOperationException: The instance of entity type 'TMS.Domain.Entities.Pais' 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.
em Microsoft.Data.Entity.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
em Microsoft.Data.Entity.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges)
em Microsoft.Data.Entity.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges)
em Microsoft.Data.Entity.ChangeTracking.EntityEntry.set_State(EntityState value)
em Microsoft.Data.Entity.DbContext.Remove[TEntity](TEntity entity)
em Microsoft.Data.Entity.Internal.InternalDbSet`1.Remove(TEntity entity)
em TMS.Infra.Data.Repositories.RepositoryBase`1.Delete(TEntity entity) na C:\Demo\src\TMS.Infra.Data\Repositories\RepositoryBase.cs:linha 56
em TMS.Domain.Services.ServiceBase`1.Delete(TEntity entity) na C:\Demo\src\TMS.Domain\Services\ServiceBase.cs:linha 52
em TMS.Domain.Services.PaisService.DeleteValidation(Pais pais) na C:\Demo\src\TMS.Domain\Services\PaisService.cs:linha 35
em TMS.Application.AppService.PaisAppService.DeleteValidation(PaisViewModel paisViewModel) na C:\Demo\src\TMS.Application\AppService\PaisAppService.cs:linha 28
em TMS.Web.Controllers.PaisesController.DeleteConfirmed(Int32 id) na C:\Demo\src\TMS.Web\Controllers\PaisesController.cs:linha 143
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
em Microsoft.AspNet.Mvc.Controllers.ControllerActionExecutor.ExecuteAsync(MethodInfo actionMethodInfo, Object instance, Object[] orderedActionArguments)
em Microsoft.AspNet.Mvc.Controllers.ControllerActionInvoker.<InvokeActionAsync>d__6.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
em Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeActionFilterAsync>d__53.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
em Microsoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeAsync>d__44.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.Mvc.Infrastructure.MvcRouteHandler.<RouteAsync>d__6.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.Routing.Template.TemplateRoute.<RouteAsync>d__27.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.Routing.RouteCollection.<RouteAsync>d__9.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
em Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
em Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
em Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
em Microsoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.IISPlatformHandler.IISPlatformHandlerMiddleware.<Invoke>d__8.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.Diagnostics.Entity.MigrationsEndPointMiddleware.<Invoke>d__5.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.Diagnostics.Entity.DatabaseErrorPageMiddleware.<Invoke>d__6.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
em Microsoft.AspNet.Diagnostics.Entity.DatabaseErrorPageMiddleware.<Invoke>d__6.MoveNext()
--- Fim do rastreamento de pilha do local anterior onde a exceção foi gerada ---
em System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
em System.Runtime.CompilerServices.TaskAwaiter.GetResult()
em Microsoft.AspNet.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()
gilmaremn commented 8 years ago

Currently own a project that dry this architecture wanted to migrate but without making major modifications.

An example of this design is that the error to delete an entity.

https://github.com/gilmaremn/EF7Demo

rowanmiller commented 8 years ago

Hey,

Looking at your code, I think it's these lines of code in PaisesController.cs that are causing your issue...

141                 PaisViewModel paisViewModel = _paisApp.GetBy(id).SingleOrDefault(); 
142 
143                 ValidationResultApp result = _paisApp.DeleteValidation(paisViewModel); 

The "query for an instance and then mark as deleted" pattern you are doing is good, the problem is that because of the various layers of abstraction you don't end up marking the actual entity instance as deleted, you attempt to tell the context that a new instance of the entity is deleted... but it has the same primary key value that was created when you queried for the entity from the database.

There are two options here:

gilmaremn commented 8 years ago

It worked perfect with AsNoTracking ();

Thank you!