防止在次要应用中创建EF模型

本文关键字:创建 EF 模型 应用 | 更新日期: 2023-09-27 18:02:37

所以我在我的应用程序的核心项目中有一个drop和重建设置,这是由我所有的应用程序在这个解决方案中消耗的。我的模型发生了很大的变化,每次我回收我的应用程序池时,我都需要删除并重新创建数据库表(应用程序现在正在快速开发中)。问题是,如果同时启动2个以上的项目,则删除和重新创建步骤会相互重叠,并且很多时候会出现丢失表的情况。

我需要一种方法来防止在运行时基于条件创建模型。我试着:

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

但这是不工作…表仍在创建中。我该怎么做呢?

防止在次要应用中创建EF模型

不太确定你的场景。

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

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创建复合模式类:

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

当然,所有提到的要点可以/必须结合起来才能得到期望的行为。但目前还不清楚,如何评估模型差异,

我的模型发生了很大的变化,我需要删除并重新创建

表示完全关于

删除和重新创建的步骤彼此重叠,很多时候有丢失的表

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