Error while deleting using Entity Framework 6 and custom repository

Asked

Viewed 705 times

3

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

"The Object cannot 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>();
    }

Exclude method in 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 layer controller:

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

I’ve tried to use 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 there returns the error:

"Attaching an Entity of type 'V1.Dominio.Entities.User' failed because other 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 have Conflicting key values. This may be because some entities are new and have not yet 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 so I removed all:

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

    }
  • I also thought that, but I did some tests and I think that is not the cause of the problem, why it finds the object, just can not delete... I am beginner yet, I do not understand much of this Objectstatemanager.

  • Related: http://answall.com/questions/51536/quando-usar-entity-framework-com-repository-pattern/80696#80696

2 answers

3

They’re both wrong, this one:

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 context an object that has been loaded before otherwise. This:

var entry = Contexto.Entry(obj);

Is of no use. Entry only locates the object in context. If the goal is deletion, a simple command like the below already excludes:

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

But by the first mistake, apparently there is a risk that the object has never been loaded. so the way is to use Entry and mark the object as deleted only, that is to say:

public virtual void Excluir(TEntity obj)
{
    // Contexto.Set<TEntity>().Remove(obj);
    Contexto.Entry(obj).State = EntityState.Deleted;
}
  • That’s how I was trying to do it, because I had: DbSet = Contexto.Set<TEntity>(); and then public virtual void Excluir(TEntity obj)&#xA; {&#xA; DbSet.Remove(obj);&#xA; } But it returns that error...

  • @Alissonsaggiorato I edited the answer. I think I get it now.

  • When I try to do it the way you showed it last, it returns the second error... I did another simpler project, without using dependency injection and viewmodels, ai it works...

1


I could not fix this error, so I decided to change the way how to delete.

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

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

Ai in the application layer, I just pass id to the domain layer:

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

That passes to the repository:

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

and in the repository the method excluded was thus:

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

And you’re running 100%!

  • I had no idea that I would need to upload the record again for your case. + 1.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.