I implemented the soft-delete pattern demonstrated by Rowan Miller during a TechEd session but I ran into an immediate problem because I am using inheritance in my Code First model. The first error was during queries because I put the IsDeleted property on my supertype (base class) but when I intercepted the query for a subtype and tried to add the filter, EF complained that there was no such property on that type. Fair enough, I moved the properties to the subtypes and that bit worked okay. But when it came to deleting, the command tree interceptor changed the delete of the subtype to an 'update set isdeleted=1' but EF also generated a delete for the supertype (base class). This caused a foreign key constraint error in the database. This is a bit of a pain but I could fix it by suppressing execution of the delete command for the supertype.
However, I cannot find a SuppressExecution method on the interception context and if I set the result to null I get a nullref exception. I guess I need some way to replace the command with a NullDbCommand, or similar. Any ideas?
public class CommandTreeInterceptor : IDbCommandTreeInterceptor
{
public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
{
if (interceptionContext.OriginalResult.DataSpace != DataSpace.SSpace) return;
// Look for query and add 'IsDeleted = 0' filter.
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);
}
// Look for delete and change it to an update instead.
var deleteCommand = interceptionContext.OriginalResult as DbDeleteCommandTree;
if (deleteCommand != null)
{
// !!! Need to suppress this whole command for supertypes (base class).
var column = SoftDeleteAttribute.GetSoftDeleteColumnName(deleteCommand.Target.Variable.ResultType.EdmType);
if (column != null)
{
var setClause =
DbExpressionBuilder.SetClause(
deleteCommand.Target.VariableType.Variable(deleteCommand.Target.VariableName)
.Property(column), DbExpression.FromBoolean(true));
var update = new DbUpdateCommandTree(deleteCommand.MetadataWorkspace,
deleteCommand.DataSpace,
deleteCommand.Target,
deleteCommand.Predicate,
new List<DbModificationClause>{ setClause }.AsReadOnly(), null);
interceptionContext.Result = update;
}
}
}
}