Error deleting using Entity Framework 6 and custom repository

3

I am using the Entity framework to do CRUD in the database, but I have an error trying to delete some item:

  

"The object can not be deleted because it was not found in the   ObjectStateManager. "

I'm using the repository pattern, unit of work and viewModels ;

My repository class:

public class Repositorio<TEntity> : IRepositorio<TEntity> where TEntity : class
   {
    private readonly ContextoManager _contextoManager = ServiceLocator.Current.GetInstance<IContextoManager>() as ContextoManager;
    protected readonly V1Contexto Contexto;
    protected DbSet<TEntity> DbSet;

    public Repositorio()
    {

        Contexto = _contextoManager.GetContexto();

        DbSet = Contexto.Set<TEntity>();
    }

The delete method in the repository class:

 public virtual void Excluir(TEntity obj)
    {
        DbSet.Remove(obj);
    }

The class of unit of work :

public class UnitOfWork : IUnitOfWork
{

    private readonly V1Contexto _dbContexto;
    private readonly ContextoManager _contextoManager = ServiceLocator.Current.GetInstance<IContextoManager>() as ContextoManager;
    private bool _disposed;

    public UnitOfWork()
    {
        _dbContexto = _contextoManager.GetContexto();
    }

    public void BeginTransaction()
    {
        _disposed = false;
    }

    public void SaveChanges()
    {
        _dbContexto.SaveChanges();
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _dbContexto.Dispose();
            }
        }
        _disposed = true;
    }

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

I have an application layer where I use the unit of work :

public void Excluir(UsuarioViewModel usuarioViewModel)
    {
        BeginTransaction();
        var usuario = Mapper.Map<UsuarioViewModel, Usuario>(usuarioViewModel);
       _usuarioService.Excluir(usuario);
       Commit();
    }

Delete in web controller controller:

    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public ActionResult DeleteConfirmed(Guid id)
    {
        var usuarioViewModel = _usuarioAppService.ObterPorId(id);
        _usuarioAppService.Excluir(usuarioViewModel);
        return RedirectToAction("Index");
    }

I have already tried to use the delete in the repository class like this:

public virtual void Excluir(TEntity obj)
    {
        var entry = Contexto.Entry(obj);

        DbSet.Attach(obj);

        entry.State = EntityState.Deleted;
    }

and also:

public virtual void Excluir(TEntity obj)
    {
        var entry = Contexto.Entry(obj);

        DbSet.Attach(obj);

        entry.State = EntityState.Deleted;

        DbSet.Remove(obj);

    }

But here the error returns:

  

"Attaching an entity of type 'V1.Domain.Entities.User' failed   because another entity of the same type already has the same primary   key value. This can happen when using the 'Attach' method or setting   the state of an entity to 'Unchanged' or 'Modified' if any entities in   the graph has conflicting key values. This may be because some   entities are new and have not received database-generated key   values. In this case use the 'Add' method or the 'Added' entity state   to track the graph and then set the state of non-new entities to   'Unchanged' or 'Modified' as appropriate. "

To do the tests, I was removing the data from the database like this, which removed all:

public virtual void Excluir(TEntity obj)
    {
    DbSet.ToList().ForEach(del => DbSet.Remove(del));

    }
    
asked by anonymous 24.06.2015 / 15:27

2 answers

1

I could not resolve this error, so I decided to change the way I deleted it.

I made my controller receive only the id instead of the object:

  [HttpPost, ActionName("Delete")]
  [ValidateAntiForgeryToken]
  public ActionResult DeleteConfirmed(Guid id)
    {    
        _usuarioAppService.Excluir(id);
        return RedirectToAction("Index");
    }

At the application layer, I just pass the id to the domain layer:

public void Excluir(Guid id)
    {
        BeginTransaction();
        //var usuario = Mapper.Map<UsuarioViewModel, Usuario>(_usuarioService.Excluir(id));
       _usuarioService.Excluir(id);
       Commit();
    }

Moving to the repository:

public void Excluir(Guid id)
    {
        _usuarioRepositorio.Excluir(id);
    }

and in the repository the delete method looks like this:

 public virtual void Excluir(Guid id)
    {
       // Contexto.Entry(obj).State = EntityState.Deleted;
        var obj = DbSet.Find(id);
        DbSet.Remove(obj);
    }

And it's running 100%!

    
25.06.2015 / 14:05
3

Both are wrong, this:

public virtual void Excluir(TEntity obj)
{
    var entry = Contexto.Entry(obj);

    DbSet.Attach(obj);

    entry.State = EntityState.Deleted;
}

and this:

public virtual void Excluir(TEntity obj)
{
    var entry = Contexto.Entry(obj);

    DbSet.Attach(obj);

    entry.State = EntityState.Deleted;

    DbSet.Remove(obj);
}

The function of Attach is to attach to the context an object that has already been loaded before in another way. This:

var entry = Contexto.Entry(obj);

It has no use whatsoever. Entry only finds the object in context. If the goal is exclusion, a simple command like the one below already excludes:

Contexto.Set<TEntity>().Remove(obj);

But by the first error, there is apparently the risk that the object has never been loaded. then the way is to use Entry and mark the object as deleted just , that is:

public virtual void Excluir(TEntity obj)
{
    // Contexto.Set<TEntity>().Remove(obj);
    Contexto.Entry(obj).State = EntityState.Deleted;
}
    
24.06.2015 / 17:59