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.

This entry was posted in 7671, 7674. Bookmark the permalink.

3 Responses to Bulk delete v4

  1. Man, your code is incredible. I have been checking your blog now like crazy.

    However, I want to ask you something, can you put your posts on some project at CodePlex (or your favorite project hosting)??
    This will be great to make it easy to play with the code. You probably already have some sample code, you don’t have to include all the tests, etc.. just something I can go through once, reference in my project and play with on my entities, and update/checkout/pull to get the next version after that. It’ll be great, and maybe it opens hands for more people to add more EF useful stuff to it!

  2. Matthieu MEZIL says:

    Thanks Mohamed
    I’m thinking about something like this.

  3. Liero says:

    I was gettig an exception “You have to specify parameter @p__linq__0″” on line:

    BulkDeletedActions.Add(() => ExecuteStoreCommand(delete.ToString(), objectQuery.Parameters.Select(p => p.Value).ToArray()));

    when executing:
    Room room = db.Room.Single(r => r.IdRoom == id);
    db.Equipment.Delete(e => e.IdRoom == id);
    db.Room.DeleteObject(room);
    db.SaveChanges();

    there was a replace:
    selectSQLQueryWithoutSelect.Replace(“@p__linq__”, “@p”)
    in condition: if (froms.Count > 1)

    I moved id outside the condition and it works in my case

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>