Bulk delete v4
In my previous post, I realized a Proof Of Concept to validate Bulk Delete feasibility for each mapping scenarios. Danny found a bug in SaveChanges method:
public override int SaveChanges(
SaveOptions options)
{
int value;
using (
TransactionScope transaction =
new TransactionScope())
{
if (_bulkDeletedActions !=
null)
foreach (
Action action
in _bulkDeletedActions)
action();
if (_bulkDeletedEntities !=
null)
foreach (
object entity
in _bulkDeletedEntities)
{
ObjectStateEntry ose;
if (ObjectStateManager.TryGetObjectStateEntry(entity,
out ose))
Detach(entity);
}
value =
base.SaveChanges(options);
transaction.Complete();
BulkDeletedActions.Clear();
BulkDeletedEntities.Clear();
BulkDeletedFuncs.Clear();
}
return value;
}
Indeed, if base.SaveChanges throws an exception, I have to attach detached entities.
I fix this bug with the following code:
public override int SaveChanges(SaveOptions options)
{
int value = 0;
using (TransactionScope transaction = new TransactionScope())
{
if (_bulkDeletedActions != null)
foreach (Action action in _bulkDeletedActions)
action();
List<object> detachedEntities = new List<object>();
if (_bulkDeletedEntities != null)
foreach (object entity in _bulkDeletedEntities)
{
ObjectStateEntry ose;
if (ObjectStateManager.TryGetObjectStateEntry(entity, out ose))
{
Detach(entity);
detachedEntities.Add(entity);
}
}
try
{
value = base.SaveChanges(options);
transaction.Complete();
BulkDeletedActions.Clear();
BulkDeletedEntities.Clear();
BulkDeletedFuncs.Clear();
}
catch (Exception e)
{
foreach (object entity in detachedEntities)
this.Attach(entity).ChangeState(EntityState.Deleted);
throw e;
}
}
return value;
}
There is no Attach method with an object parameter and moreover Attach and AttachTo framework methods don’t return anything.
However, I think that such a method might be helpful and more helpful yet if it returns an ObjectStateEntry.
So I add my own extension methods:
public static class ObjectContextExtension
{
public static ObjectStateEntry Attach(this ObjectContext context, object entity)
{
context.AttachTo(context.GetEntitySet(entity.GetType()).Name, entity);
return context.ObjectStateManager.GetObjectStateEntry(entity);
}
public static EntitySet GetEntitySet(this ObjectContext context, EntityType entityType)
{
List<EntitySet> entitySets = context.MetadataWorkspace.GetItems(DataSpace.CSpace).OfType<EntityContainer>().First().BaseEntitySets.OfType<EntitySet>().ToList();
EntityType loopEntityType = entityType;
EntitySet entitySet;
while ((entitySet = entitySets.FirstOrDefault(es => es.ElementType == loopEntityType)) == null && loopEntityType.BaseType != null)
loopEntityType = (EntityType)loopEntityType.BaseType;
if (entitySet == null)
throw new InvalidOperationException();
return entitySet;
}
public static EntitySet GetEntitySet(this ObjectContext context, Type type)
{
return GetEntitySet(context, context.MetadataWorkspace.GetItems(DataSpace.CSpace).OfType<EntityType>().First(et => et.Name == type.Name));
}
}
This will be good now.
Thanks again to Danny for the attention he took to my post.