View on GitHub

Entity Framework Conventions

Download this project as a .zip file Download this project as a tar.gz file

EFConvention

EFConvention is a convention based extension library for Entity Framework to automate several tasks currently cumbersome to do. It allows developers to create an Entity Framework based Context without having to specify each entity by putting it as DbSet<> as property.

NuGet: http://www.nuget.org/packages/EFConvention/

Basic usage

1) Create the context factory

private IAutoContextFactory _autoContextFactory;
_autoContextFactory = new AutoContextFactory();
_autoContextFactory.AddEntitiesBasedOn<BaseEntity>().AddAssemblyContaining<BaseEntity>();

2) Configure the factory

a) Use context factory configuration:

_autoContextFactory.Configuration.AutoGeneratedMigrationsEnabled = true; 
_autoContextFactory.Configuration.AutoMigrateGeneratedMigrationsEnabled = true;
_autoContextFactory.Configuration.MigrationsDirectory = @"ProjectDir\Migrations";

b) Or use conventions:

public class ConventionConfiguration : IEFConventionConfigurator
{
    public void Configure(IAutoContextFactoryConfiguration configuration)
    {
        configuration.AutoGeneratedMigrationsEnabled = true;
        configuration.AutoMigrateGeneratedMigrationsEnabled = true;
        configuration.MigrationsDirectory = @"ProjectDir\Migrations\";
    }
}

3) Create the context and use it

var context = _autoContextFactory.Context();
context.Set<Item>().Add(new Item());
context.SaveChanges();

Detailed info

Lifecycle

Factory lifecyle should be same as your application lifecycle. First Context() call checks if database has already been migrated, provided AutoMigrateGeneratedMigrationsEnabled is set to true. If you manage migrations manually, lifecycle can be anything and you will be responsible for performance and errors. DbContext lifecycle can be anything you would normally set a standard DbContext to, in Web cases it would be per Request.

Context

From versioni 2.4, EFConvention uses a standard DbContext. Use the Context() call as such.

Context() call from Factory also accepts a string parameter for connection string, either full connectionstring or the name of it, just like standard DbContext. It's suggested to just set the Connection option under Configuration property, though.

Configuration

IAutoContextFactoryConfiguration provides several configuration options.

NB! Order of operations is important. Any configuration should be done before Context(), MigrateToLatest() or GenerateMigrations() are called for the first time on Factory, although before migrating, anything ought to work.

Factory

public class EntityBase
{
  public int Id { get; set;
}

public class EntityOne : EntityBase {}
public class EntityTwo : EntityBase {}

factory.AddEntitiesBasedOn<EntityBase>().AddAssemblyContaining<EntityOne>(); 
// Adds EntityOne and EntityTwo to context

NB! Order of operations is important. Any other method should be called before Context(), MigratToLatest() or GenerateMigrations() are called for the first time on Factory

Model Builder Conventions

Starting from version 2.1, EFConvention supports NHibernate-style convention based model building. These classes are IModelBuilderOverride type and take an entity that you wish to map as a generic argument. They will be automatically picked up as long as they're in one of the assemblies you added using AddAssemblyContaining<T>() or AddAssembly(Assembly assembly)

public class ItemOverride : IModelBuilderOverride<Item>
{
    public void Configure(EntityTypeConfiguration<Item> entity)
    {
        entity.ToTable("MyTable");
        // Insert your mapping code here
    }
}

Listener Conventions

Starting from version 2.1, EFConvention also supports NHibernate style event listeners that can be hooked to different types of events in both pre and post save. Those, too, will be picked up automatically as long as they are located within the assmblies to be searched for items. Full list can be found under EFConvention.Interceptors namespace. The IPreEventListener and IPostEventListener react to any type of entity state.

public class MyEventListener : IPreInsertEventListener
{
    void OnInsert(DbEntityEntry entityEntry)
    {
        if(entityEntry.Entity is BaseEntity)
            ((BaseEntity)entityEntry.Entity).Created = DateTime.Now;
    }
}

Configuration conventions

Starting from version 2.3, EFConvention has a support for automatic EFConvention configuration. Simply create a class that inherits from IEFConventionConfigurator and either stick it into an assembly that you have added via fluent setup and you're good to go:

public class ConventionConfiguration : IEFConventionConfigurator
{
    public void Configure(IAutoContextFactoryConfiguration configuration)
    {
        configuration.AutoGeneratedMigrationsEnabled = true;
        configuration.AutoMigrateGeneratedMigrationsEnabled = true;
        configuration.MigrationsDirectory = @"ProjectDir\Migrations\";
    }
}

The alternative is, of course, to just configure it when you're setting up your context, such as in Resolve(Component.For()) for Windsor or kernel.Bind() for Ninject.

Seeding conventions

Starting from version 2.3, EFConvention also has a support for loading seeding via conventions. EFConvention supports two types of seeding (both can be used concurrently) and as long as they are included in the assembly list, they will be picked up:

public class ItemSeed : IEntitySeed<Item>
{
    public void Seed(DbSet<Item> entity)
    {
        entity.AddOrUpdate(a => a.Data, new Item() {Data = "Hello world", Created = DateTime.Now});
    }
}
public class AllSeed : IContextSeed
{
    public void Seed(DbContext context)
    {
        context.Set<EntityTwo>().AddOrUpdate(x => x.Name, new EntityTwo() {Name = "My entity"});
    }
}

Events

All events fire before their original base events

IContext Events

As of version 2.4, IContext has been removed in favor of standard DbContext.

IAutoContextFactory Events

factory.Seeding += (sender, args) => { args.Context.(...); /* args.Context is DbContext */ };
context.ModelCreating += (sender, args) => { args.ModelBuilder.(...);/* args.ModelBuilder is standard DbModelBuilder */};

Version history

v 2.4.0

v 2.3.4

v 2.3

v 2.2

v 2.1

v 2.0

v 1.0.3

v 1.0.2

v 1.0.1

v 1.0

TODO

Known bugs