防止在辅助应用程序中创建EF模型

时间:2016-08-17 00:32:18

标签: c# entity-framework

所以我在我的应用程序的核心项目中有一个删除并重新创建设置,该项目由我的所有应用程序使用。我的模型变化足够大,我需要这个drop并在每次我回收我的应用程序池时重新创建数据库表(app现在处于快速开发阶段。)问题是如果2个项目同时启动,删除并重新创建彼此的步骤,并多次丢失表。

我需要一种方法来防止在运行时根据条件创建模型。我试过了:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    if (condition) 
        return;
    //...

    base.OnModelCreating(modelBuilder);
}

但这不起作用......表仍在创建中。我怎么能这样做?

2 个答案:

答案 0 :(得分:1)

对您的情况不太确定。

出于开发目的,您可以为表使用不同的模式。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.HasDefaultSchema("applicationX");
}

如果无法做到这一点,您可以为实体添加后缀/前缀表名称。

如果您需要两个应用程序共享表(数据),您可以在共享相同模型构建代码的任何应用程序中组合所有数据库。

然后,当然,您必须以某种方式为您的数据库娱乐代码(https://github.com/aspnet/EntityFramework/issues/3042)创建“关键部分”,使用互斥锁或/并将其组合,例如使用您自己的数据库中的锁同步对象(表)。

如果需要动态构建模型(数据库),例如,使用依赖注入在单个DB上下文中动态构建模型:

/// <summary>
/// Formalization of entity framework DbContext model creation <see cref="DbContext.OnModelCreating"/>
/// </summary>
/// <remarks>
/// The reason for this explicit interface of the <see cref="DbContext.OnModelCreating"/> is to make compositions of several model builders into one
/// </remarks>
public interface IEntityFrameworkModelBuilder
{
    void BuildModel(ModelBuilder modelBuilder);
}

public abstract class DbContextBase : DbContext
{

    protected DbContextBase(DbContextOptions options, IEntityFrameworkModelBuilder modelBuilder) : base(options)
    {
        _modelBuilder = modelBuilder;
    }

    public virtual IEntityFrameworkModelBuilder ModelBuilder
    {
        get { return _modelBuilder ?? (_modelBuilder = new DefaultSchemaEntityFrameworkModelBuilder("dbo")); }
        protected set { _modelBuilder = value; }
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        ModelBuilder.BuildModel(modelBuilder);
    }
}

当然,你可以创建例如IEntityFrameworkModelBuilder的composit模式类:

/// <summary>
/// The composition of <see cref="IEntityFrameworkModelBuilder"/> used to construct <see cref="DbContext"/> model creation from several modules (tests).
/// </summary>
/// <seealso cref="DbContextOnModelCreatingAdaptingModelBuilder"/>
public class EntityFrameworkModelBuilderComposition : IEntityFrameworkModelBuilder, IList<IEntityFrameworkModelBuilder>
{
    private readonly IList<IEntityFrameworkModelBuilder> _builders;

    public EntityFrameworkModelBuilderComposition() : this(new IEntityFrameworkModelBuilder[0])
    {}

    public EntityFrameworkModelBuilderComposition(params IEntityFrameworkModelBuilder[] builders)
    {
        _builders = new List<IEntityFrameworkModelBuilder>(builders);
    }

    /// <summary>
    /// Constructor to take list of builders as underlaying list so it is initialized with these builders and sharing the same reference.
    /// </summary>
    /// <param name="builders"></param>
    public EntityFrameworkModelBuilderComposition(IList<IEntityFrameworkModelBuilder> builders)
    {
        _builders = builders ?? new List<IEntityFrameworkModelBuilder>();
    }

    public virtual void BuildModel(ModelBuilder modelBuilder)
    {
        foreach (var b in _builders)
        {
            b.BuildModel(modelBuilder);
        }
    }
}

只需添加,迟早会发现有用的内容:

/// <summary>
/// The <see cref="IEntityFrameworkModelBuilder"/> implementation of a building model on the base of <see cref="DbContext"/> instance calling its <see cref="DbContext.OnModelCreating"/> protected method.
/// </summary>
/// <seealso cref="DbContextOnModelCreatingAdaptingModelBuilder"/>
/// <seealso cref="EntityFrameworkModelBuilderComposition"/>
public class DbContextOnModelCreatingAdaptingModelBuilder : IEntityFrameworkModelBuilder
{
    private readonly Func<DbContext> _dbContextFactoryMethod;

    public DbContextOnModelCreatingAdaptingModelBuilder(Func<DbContext> dbContextFactoryMethod)
    {
        _dbContextFactoryMethod = dbContextFactoryMethod;
    }

    public void BuildModel(ModelBuilder modelBuilder)
    {
        using (var dbContext = _dbContextFactoryMethod())
        {
            MethodInfo onModelCreating = dbContext.GetType().GetMethod("OnModelCreating", BindingFlags.NonPublic | BindingFlags.Instance);
            onModelCreating.Invoke(dbContext, new object[] {modelBuilder});
        }
    }
}

当然,所有提到的点都可以/必须结合起来以获得所需的行为。但目前尚不清楚,您如何评估模型差异,

  

我的模型变化足够大,我需要这个drop并重新创建

完全是指

  

删除并重新创建彼此的步骤,并多次丢失表

答案 1 :(得分:0)

可悲的是,根据微软的说法,似乎没有办法做到这一点:https://github.com/aspnet/EntityFramework/issues/6346