• 2015-10-21
  • Updated packages to depend on EF6
  • Merged IAuditable interface into Isg.EntityFramework.Interceptors.Auditable
  • Merged ISoftDelete interface into Isg.EntityFramework.Interceptors.ISoftDelete
  • Removed Isg.Domain as a package.
  • Removed Isg.EntityFramework.ObservableProvider as a package.
  • There were some incompatibilities with EF6 that I didn't have time to resolve.
    • I originally wrote this project to support using Application Roles with Entity Framework. There is an EF6 alternative now.
    • The code is still in the repository, so if you want it and can get the tests passing again, I'll accept your PR.



  1. Your bootstrapper code should initialize the InterceptorProvider.

    csharp var softDelete = new SoftDeleteChangeInterceptor(); var auditable = new AuditableChangeInterceptor(); var interceptorProvider = new DefaultInterceptorProvider(softDelete, auditable); InterceptorProvider.SetInterceptorProvider(interceptorProvider);

  2. Your DbContext must inherit from DbContextBase.

  3. Profit!


Provides the ISoftDelete interface.

The SoftDeleteChangeInterceptor provides the following behavior for any entity implementing ISoftDelete.

The entity will not be deleted and will instead have it's IsDeleted property set to true.


Provides the IAuditable interface.

The AuditableChangeInterceptor will provide the following behaviors for any entity implementing IAuditable

During Insert

  • Set CreateDate to current time
  • Set CreateUser to current user
  • Set UpdateDate to current time
  • Set UpdateUser to current user

During Update

  • Set UpdateDate to current time
  • Set UpdateUser to current user


Provides an IQueryable implementation of the Specification Pattern.


Given the following Specification class:

public class CustomerSpecification : CompositeSpecification<Customer>
    public string Name { get; set; }
    public bool? HasInvoices { get; set; }

    protected override IEnumerable<Expression<Func<Customer, bool>>> GetExpressions()
        if (!string.IsNullOrWhiteSpace(Name))
            yield return ByName();

        if (HasInvoices.HasValue)
            yield return ByHasInvoices();

    private Expression<Func<Customer, bool>> ByHasInvoices()
        if (HasInvoices.Value)
            return c => c.Invoices.Any();
        return c => !c.Invoices.Any();

    private Expression<Func<Customer, bool>> ByName()
        return c => c.Name.StartsWith(Name);

You can execute code like this:

    var specification = new CustomerSpecification()
                            Name = "Fred",
                            HasInvoices = true,

    using (var context = new CustomerDbContext())
        var query = context.Customers

This approach to queries is useful when you want to allow your clients to define queries in a declarative fashion.