Skip to content

Instantly share code, notes, and snippets.

@marisks
Created February 27, 2016 06:46
Show Gist options
  • Save marisks/3cc2e4f18048e2f0b7a5 to your computer and use it in GitHub Desktop.
Save marisks/3cc2e4f18048e2f0b7a5 to your computer and use it in GitHub Desktop.

Revisions

  1. marisks created this gist Feb 27, 2016.
    64 changes: 64 additions & 0 deletions CreatedAndModifiedDateInterceptor.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,64 @@
    using System;
    using System.Data.Entity.Core.Common.CommandTrees;
    using System.Data.Entity.Core.Metadata.Edm;
    using System.Data.Entity.Infrastructure.Interception;
    using System.Linq;

    public class CreatedAndModifiedDateInterceptor : IDbCommandTreeInterceptor
    {
    public const string CreatedColumnName = "Created";
    public const string ModifiedColumnName = "Modified";

    public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
    {
    if (interceptionContext.OriginalResult.DataSpace != DataSpace.SSpace)
    {
    return;
    }

    var insertCommand = interceptionContext.Result as DbInsertCommandTree;
    if (insertCommand != null)
    {
    interceptionContext.Result = HandleInsertCommand(insertCommand);
    }

    var updateCommand = interceptionContext.OriginalResult as DbUpdateCommandTree;
    if (updateCommand != null)
    {
    interceptionContext.Result = HandleUpdateCommand(updateCommand);
    }
    }

    private static DbCommandTree HandleInsertCommand(DbInsertCommandTree insertCommand)
    {
    var now = DateTime.Now;

    var setClauses = insertCommand.SetClauses
    .Select(clause => clause.UpdateIfMatch(CreatedColumnName, DbExpression.FromDateTime(now)))
    .Select(clause => clause.UpdateIfMatch(ModifiedColumnName, DbExpression.FromDateTime(now)))
    .ToList();

    return new DbInsertCommandTree(
    insertCommand.MetadataWorkspace,
    insertCommand.DataSpace,
    insertCommand.Target,
    setClauses.AsReadOnly(),
    insertCommand.Returning);
    }

    private static DbCommandTree HandleUpdateCommand(DbUpdateCommandTree updateCommand)
    {
    var now = DateTime.Now;

    var setClauses = updateCommand.SetClauses
    .Select(clause => clause.UpdateIfMatch(ModifiedColumnName, DbExpression.FromDateTime(now)))
    .ToList();

    return new DbUpdateCommandTree(
    updateCommand.MetadataWorkspace,
    updateCommand.DataSpace,
    updateCommand.Target,
    updateCommand.Predicate,
    setClauses.AsReadOnly(), null);
    }
    }
    10 changes: 10 additions & 0 deletions EntityFrameworkConfiguration.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    using System.Data.Entity;

    public class EntityFrameworkConfiguration : DbConfiguration
    {
    public EntityFrameworkConfiguration()
    {
    AddInterceptor(new SoftDeleteInterceptor());
    AddInterceptor(new CreatedAndModifiedDateInterceptor());
    }
    }
    46 changes: 46 additions & 0 deletions Extensions.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,46 @@
    using System;
    using System.Data.Entity.Core.Common.CommandTrees;
    using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;

    public static class Extensions
    {
    public static DbModificationClause UpdateIfMatch(
    this DbModificationClause clause,
    string property,
    DbExpression value)
    {
    return clause.IsFor(property)
    ? DbExpressionBuilder.SetClause(clause.Property(), value)
    : clause;
    }

    public static bool IsFor(
    this DbModificationClause clause,
    string property)
    {
    return clause.HasPropertyExpression()
    && clause.Property().Property.Name == property;
    }

    public static DbPropertyExpression Property(
    this DbModificationClause clause)
    {
    if (clause.HasPropertyExpression())
    {
    var setClause = (DbSetClause) clause;
    return (DbPropertyExpression) setClause.Property;
    }

    var message =
    "clause does not contain property expression. " +
    "Use HasPropertyExpression method to check if it has property expression.";
    throw new Exception(message);
    }

    public static bool HasPropertyExpression(
    this DbModificationClause modificationClause)
    {
    var setClause = modificationClause as DbSetClause;
    return setClause?.Property is DbPropertyExpression;
    }
    }
    81 changes: 81 additions & 0 deletions SoftDeleteInterceptor.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,81 @@
    using System.Collections.Generic;
    using System.Data.Entity.Core.Common.CommandTrees;
    using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
    using System.Data.Entity.Core.Metadata.Edm;
    using System.Data.Entity.Infrastructure.Interception;
    using System.Linq;

    public class SoftDeleteInterceptor : IDbCommandTreeInterceptor
    {
    public const string IsDeletedColumnName = "IsDeleted";

    public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
    {
    if (interceptionContext.OriginalResult.DataSpace != DataSpace.SSpace)
    {
    return;
    }

    var queryCommand = interceptionContext.Result as DbQueryCommandTree;
    if (queryCommand != null)
    {
    interceptionContext.Result = HandleQueryCommand(queryCommand);
    }

    var deleteCommand = interceptionContext.OriginalResult as DbDeleteCommandTree;
    if (deleteCommand != null)
    {
    interceptionContext.Result = HandleDeleteCommand(deleteCommand);
    }
    }

    private static DbCommandTree HandleQueryCommand(DbQueryCommandTree queryCommand)
    {
    var newQuery = queryCommand.Query.Accept(new SoftDeleteQueryVisitor());
    return new DbQueryCommandTree(
    queryCommand.MetadataWorkspace,
    queryCommand.DataSpace,
    newQuery);
    }

    private static DbCommandTree HandleDeleteCommand(DbDeleteCommandTree deleteCommand)
    {
    var setClauses = new List<DbModificationClause>();
    var table = (EntityType) deleteCommand.Target.VariableType.EdmType;

    if (table.Properties.All(p => p.Name != IsDeletedColumnName))
    {
    return deleteCommand;
    }

    setClauses.Add(DbExpressionBuilder.SetClause(
    deleteCommand.Target.VariableType.Variable(deleteCommand.Target.VariableName).Property(IsDeletedColumnName),
    DbExpression.FromBoolean(true)));

    return new DbUpdateCommandTree(
    deleteCommand.MetadataWorkspace,
    deleteCommand.DataSpace,
    deleteCommand.Target,
    deleteCommand.Predicate,
    setClauses.AsReadOnly(), null);
    }

    public class SoftDeleteQueryVisitor : DefaultExpressionVisitor
    {
    public override DbExpression Visit(DbScanExpression expression)
    {
    var table = (EntityType)expression.Target.ElementType;
    if (table.Properties.All(p => p.Name != IsDeletedColumnName))
    {
    return base.Visit(expression);
    }

    var binding = expression.Bind();
    return binding.Filter(
    binding.VariableType
    .Variable(binding.VariableName)
    .Property(IsDeletedColumnName)
    .NotEqual(DbExpression.FromBoolean(true)));
    }
    }
    }