Search code examples
databaseentity-frameworkentity-framework-6soft-delete

Entity Framework 6 Disable Interception temporarily


I am using an IDbCommandTreeInterceptor to enable soft deletes on my model.

System.Data.Entity.Infrastructure.Interception.DbInterception.Add(
     new SoftDeleteInterception());

I want to be able to disable the interceptor temporarily so that I can select a "deleted" entity for auditing purposes.

However, It seems like the DbInterception collection is assembly-wide.

Is there any way to create a new DbContext without interception on? Or even a way to add the interceptor to the DbContext every time it is created?


Solution

  • I have extended my db context class with additional property

    [DbConfigurationType(typeof(DbConfig))] 
    public partial class YourEntitiesDB 
    {
        public bool IgnoreSoftDelete { get; set; }
    }
    

    Then in the TreeCreated(...) method i check this flag and if true then it just doesn't go further to the QueryVisitor

    public class SoftDeleteInterceptor : IDbCommandTreeInterceptor
    {
        public SoftDeleteInterceptor()
        {
    
        }
        public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
        {
            var db = interceptionContext.DbContexts.FirstOrDefault() as YourEntitiesDB;
            if (db!=null && db.IgnoreSoftDelete)
            {
                // Ignore soft delete interseptor (Used in archives)
                return;
            }
    
            if (interceptionContext.OriginalResult.DataSpace == DataSpace.CSpace)
            {
                var queryCommand = interceptionContext.Result as DbQueryCommandTree;
                if (queryCommand != null)
                {
                    var newQuery = queryCommand.Query.Accept(new SoftDeleteQueryVisitor());
                    interceptionContext.Result = new DbQueryCommandTree(
                        queryCommand.MetadataWorkspace,
                        queryCommand.DataSpace,
                        newQuery);
                }
    
                var deleteCommand = interceptionContext.OriginalResult as DbDeleteCommandTree;
                if (deleteCommand != null)
                {
                    var column = SoftDeleteAttribute.GetSoftDeleteColumnName(deleteCommand.Target.VariableType.EdmType);
                    if (column != null)
                    {
                        var setClauses = new List<DbModificationClause>();
                        var table = (EntityType)deleteCommand.Target.VariableType.EdmType;
                        if (table.Properties.Any(p => p.Name == column))
                        {
                            setClauses.Add(DbExpressionBuilder.SetClause(
                                    DbExpressionBuilder.Property(
                                        DbExpressionBuilder.Variable(deleteCommand.Target.VariableType, deleteCommand.Target.VariableName),
                                        column),
                                    DbExpression.FromBoolean(true)));
                        }
    
                        var update = new DbUpdateCommandTree(
                            deleteCommand.MetadataWorkspace,
                            deleteCommand.DataSpace,
                            deleteCommand.Target,
                            deleteCommand.Predicate,
                            setClauses.AsReadOnly(),
                            null);
    
                        interceptionContext.Result = update;
                    }
                }
            }
        }
    }
    

    In order to use it i just set the flag to true when needed

    YuorEntitiesDB DB = new YuorEntitiesDB();
    DB.IgnoreSoftDelete = true;
    DB.Records.Where(...)