Search code examples
c#invalidoperationexceptionentityspaces

CombineDeletedEntities/SeparateDeletedEntities Adding Duplicate Entities


I have a grid with the datasource set to an EntitySpaces collection, with a checkbox column. When the checkbox is checked, I want to create a record and when it is cleared I want to delete the same record.

To avoid the obvious PK violation save if a user repeatedly checks and unchecks an item, I am trying to retrieve the previously deleted entities and mark them as not deleted. However, when I use CombineDeletedEntities and SeparateDeletedEntities on the collection it creates duplicate entries in the collection.

roleFunctions.CombineDeletedEntities();

// On third cycle through, this is the error line
RoleFunction foundItem = roleFunctions.FindByPrimaryKey(roleName, functionName);

if (foundItem != null) 
{
    foundItem.RowState = esDataRowState.Unchanged;

    // Extraneous logic...
}
else
{
    // Create new item...
}

roleFunctions.SeparateDeletedEntities();

So basically when I do FindByPrimaryKey the third time, EntitySpaces has created an extra item somehow which causes an InvalidOperationException with a message of Sequence contains more than one matching element.

Has anyone hit this with EntitySpaces before and how did you end up nicely handling a user creating and deleting the same entity multiple times in a single session?


Solution

  • This was a fairly easy fix, especially since EntitySpaces is open source. The two methods I was using to avoid creating duplicate records are shown below:

    public override void CombineDeletedEntities()
    {
        if (this.deletedEntities != null && this.deletedEntities.Count > 0)
        {
            foreach (T entity in deletedEntities)
            {
                entities.Add(entity);
            }
        }
    }
    
    public override void SeparateDeletedEntities()
    {
        foreach (T entity in this.entities)
        {
            if (entity.rowState == esDataRowState.Deleted)
            {
                if (deletedEntities == null)
                {
                    deletedEntities = new BindingList<T>();
                }
    
                deletedEntities.Add(entity);
            }
        }
    
        if (this.deletedEntities != null && this.deletedEntities.Count > 0)
        {
            foreach (T entity in deletedEntities)
            {
                entities.Remove(entity);
            }
        }
    }
    

    Looking at the above it becomes fairly obvious that the code will continue adding back the same entities into the deletedEntities list every time we call SeparateDeletedEntities.

    The easy solution was to clear the deletedEntities collection when the are combined with the collection proper:

    public override void CombineDeletedEntities()
    {
        if (this.deletedEntities != null && this.deletedEntities.Count > 0)
        {
            foreach (T entity in deletedEntities)
            {
                entities.Add(entity);
            }
    
            this.deletedEntities.Clear();
        }
    }
    

    The downside to this quick and dirty fix is that you probably don't want to call collection.Save() after calling CombineDeletedEntities until you have called SeparateDeletedEntities, since having an empty deletedEntities collection will probably cause your save to skip all deletes.

    I would have liked to just add a if (!deletedEntities.Contains(entity)) call in the SeparateDeletedEntities routine, but the equality comparison sees the entities as different so I went with the simpler solution.