Reputation: 480
I am working on an application, which will be extendable via plugins using MEF. The application is using Entity Framework. The context is created by factory method:
public class DataContextFactory
{
[ImportingConstructor]
public DataContextFactory([ImportMany] IEnumerable<IModelCreator> modelCreators, [Import(AllowDefault = true)]IDatabaseInitializer<DataContext> initializer)
{
ModelCreators = modelCreators;
Initializer = initializer ?? new DefaultDataContextInitializer();
}
public DbContext Create()
{
return new DataContext(ModelCreators, Initializer);
}
}
public interface IModelCreator
{
void OnModelCreating(DbModelBuilder modelBuilder);
}
public class DataContext : DbContext
{
public DataContext(IEnumerable<IModelCreator> modelCreators, IDatabaseInitializer<DataContext> initializer)
{
ModelCreators = modelCreators;
if (initializer != null)
{
Database.SetInitializer(initializer);
}
}
private IEnumerable<IModelCreator> ModelCreators { get; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
foreach (var creator in ModelCreators)
{
creator.OnModelCreating(modelBuilder);
}
}
}
where each plugin defines it's own IModelCreator
.
Entities will be then accessed by `DbContext.Set().
The problem is that EF won't create additional tables, it will either drop the db or throw exception (depending on initializer used). When I turn on migrations, I am not able to generate migration, because there is no model in project, where the DbContext
is.
Will each plugin have to supply SQL script to create it's tables or is there a way for EF to add tables at runtime for entities imported with plugin?
If I implement my own IDatabaseInitializer
how can I tell it to create missing tables?
Upvotes: 3
Views: 650
Reputation: 480
I have used MigrateDatabaseToLatestVersion<TContext, TMigrationsConfiguration> Class.
I have created CompositeDataContextInitializer
and changed my DataContextFactory
to pass it to my DataContext
as argument.
public class CompositedDataContextInitializer : MigrateDatabaseToLatestVersion<DataContext, Migrations.MigrationConfiguration>
{
protected virtual void Seed(DataContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
foreach (var seeder in ServiceLocator.Current.GetAllInstances<IDataSeeder>())
{
seeder.Seed(context);
}
}
}
[Export(typeof(IDbContextFactory<DbContext>))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class ContextFromCompositionFactory : IDbContextFactory<DbContext>, IDbContextFactory<DataContext>
{
public DbContext Create() => new DataContext(ServiceLocator.Current.GetAllInstances<IModelCreator>(), new CompositedDataContextInitializer());
DataContext IDbContextFactory<DataContext>.Create() => (DataContext)Create();
}
public interface IModelCreator
{
void OnModelCreating(DbModelBuilder modelBuilder);
}
public class DataContext : DbContext
{
public DataContext(IEnumerable<IModelCreator> modelCreators, IDatabaseInitializer<DataContext> initializer)
{
ModelCreators = modelCreators;
if (initializer != null)
{
Database.SetInitializer(initializer);
}
}
private IEnumerable<IModelCreator> ModelCreators { get; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
foreach (var creator in ModelCreators)
{
creator.OnModelCreating(modelBuilder);
}
}
}
There are still some problems with TPT Inheritance; if you want to store new classes which inherit from classes already in system, use TPH Inheritance.
Upvotes: 1