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?
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
}