Entity Framework:根据在 MEF 中找到的插件动态更改模型

Entity Framework: dynamically change model based on plugins found with MEF

我正在开发一个应用程序,该应用程序可以使用 MEF 通过插件进行扩展。该应用程序正在使用 Entity Framework。上下文是通过工厂方法创建的:

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);
        }
    }
}

每个插件定义它自己的 IModelCreator。 然后将通过`DbContext.Set().

访问实体

问题是 EF 不会创建额外的表,它会删除数据库或抛出异常(取决于使用的初始化程序)。当我打开迁移时,我无法生成迁移,因为项目中没有模型,DbContext 所在的位置。

每个插件是否必须提供 SQL 脚本来创建它的表,或者 EF 是否有办法在运行时为使用插件导入的实体添加表?

如果我实现自己的 IDatabaseInitializer 我如何告诉它创建缺失的表?

我用过MigrateDatabaseToLatestVersion<TContext, TMigrationsConfiguration> Class.

我创建了 CompositeDataContextInitializer 并更改了我的 DataContextFactory 以将其作为参数传递给我的 DataContext

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);
        }
    }
}

TPT Inheritance; if you want to store new classes which inherit from classes already in system, use TPH Inheritance还有一些问题。