.netentity-frameworkpocoentity-framework-ctp5

Having trouble trying to Delete a POCO object in Entity Framework CTP5


I'm having a problem trying to delete a POCO object with my Entity Framework CTP5 code.

I'll start out with my Delete method and then both Integration Tests. First Integration Test passes/works, second doesn't.

public class GenericRepository<T> : IRepository<T> where T : class
{
  public GenericRepository(DbContext unitOfWork)
  {
    Context = unitOfWork;
  }

  ...

  public void Delete(T entity)
  {
    if (entity == null)
    {
      throw new ArgumentNullException("entity");
    }

    if (Context.Entry(entity).State == EntityState.Detached)
    {
      Context.Entry(entity).State = EntityState.Deleted;
    }
    Context.Set<T>().Remove(entity);
  }

  ...
}

So that's my generic repo with a Delete method.

Ok.. now to my Integration Tests....

[TestMethod]
public void DirectlyDeleteAPoco()
{
  // Arrange.
  var poco = new Poco {PocoId = 1};

  // Act.
  using (new TransactionScope())
  {
    PocoRepository.Delete(poco);
    UnitOfWork.Commit();

    // Now try and reload this deleted object.
    var pocoShouldNotExist =
      PocoRepository.Find()
      .WithId(1)
      .SingleOrDefault();

    Assert.IsNull(pocoShouldNotExist);
  }
}

that works, this doesn't...

[TestMethod]
public void DeleteAPocoAfterLoadingAnInstance()
{
  // Arrange.
  var existingPoco = PocoRepository.Find().First();
  var detachedPoco = new Poco {PocoId = existingPoco.PocoId};

  // Act.
  using (new TransactionScope())
  {
    PocoRepository.Delete(detachedPoco );
    UnitOfWork.Commit();

    // Now try and reload this deleted object.
    var pocoShouldNotExist =
      PocoRepository.Find()
      .WithId(existingPoco.PocoId)
      .SingleOrDefault();

    Assert.IsNull(pocoShouldNotExist);
  }
}

This second one throws the following exception :-

System.InvalidOperationException: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.

Now, if I understand that correctly, I'm trying to add a second Poco object (ie detachedPoco) to the Object Graph .. but I can't because one already exists (the existingPoco I pre-loaded). Ok ... but I feel like I shouldn't care about this. As a consumer, I don't want to care about these ObjectManagers and stuff. I just want to have my poco's just save/delete.

How can I change my Delete method to reflect these scenarios? Please?


Solution

  • You are right. Deleting is just wrapper around Attach and set state to Deleted - it is the only way how ObjectContext (wrapped in DbContext) can know that it has to delete object.

    I guess you can try to use new CTP5 feature of DbSet - Local and try to find attached entity with the same Id first:

    var attached = Context.Set<T>().Local.FirstOrDefault(e => e.Id == entity.Id);
    if (attached != null)
    {
     // Delete attached
    }
    else
    {
     // Delete entity
    }