EntityFramework Core自动迁移

Enr*_*ico 1 entity-framework-core asp.net-core microsoft-identity-web

在我的项目中,我有 2 个数据库:一个是我的自定义数据库,另一个是ApplicationDbContextMicrosoft Identity我的。

在我的Startup.cs我有这样的代码:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
        ApplicationDbContext db, MyContext dbPSC)
{
     // ...

    db.Database.EnsureCreated();
    db.Database.Migrate();

    dbPSC.Database.EnsureCreated();
    dbPSC.Database.Migrate();
}
Run Code Online (Sandbox Code Playgroud)

不知道什么时候有迁移的迁移吧?然后,我有两个错误:

  • 除了第一次之外,每次应用程序启动时,迁移都会ApplicationDbContext引发错误
  • 我的上下文的迁移似乎很好

使用的最佳做法是什么?是否需要打电话进行迁移ApplicationDbContext

更新

我已经删除了该Migration文件夹。然后,改变了Startup.cs类似

public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
        ApplicationDbContext db, MyContext dbPSC)
{
     // ...

    db.Database.EnsureCreated();
    dbPSC.Database.EnsureCreated();
}
Run Code Online (Sandbox Code Playgroud)

但是当应用程序启动时,它根本不创建任何表。AuditDbContext是因为我使用Audit.net

public class MyContext : AuditDbContext
{
    public MyContext(DbContextOptions<MyContext> options) : base(options) { }

    public DbSet<Message> Messages { get; set; }
    public DbSet<AuditMessage> Audit_Messages { get; set; }

    #region Common Tables
    public DbSet<Country> Countries { get; set; }
    public DbSet<AuditCountry> Audit_Countries { get; set; }
    #endregion
    #region Seed
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Seed();
    }
    #endregion
}
Run Code Online (Sandbox Code Playgroud)

更新#2

我尝试了另一种解决方案,但它不起作用。解决方案是使用RelationalDatabaseCreator如下代码

public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
        ApplicationDbContext db, MyContext dbPSC)
{
     // ...

    db.Database.EnsureCreated();
    dbPSC.Database.EnsureCreated();
    RelationalDatabaseCreator databaseCreator = 
     (RelationalDatabaseCreator)context.Database.GetService<IDatabaseCreator>();
    databaseCreator.CreateTables();
}
Run Code Online (Sandbox Code Playgroud)

作为Migrate(),应用程序第一次运行时会创建表,但第二次会引发错误,因为这些表已存在于数据库中。

MrV*_*ype 5

问题很可能是您正在拨打的电话EnsureCreated()

来自文档

请注意,此 API 不使用迁移来创建数据库。此外,创建的数据库以后无法使用迁移进行更新。如果您的目标是关系数据库并使用迁移,则可以使用 DbContext.Database.Migrate() 方法来确保创建数据库并应用所有迁移

So, it's enough to call Migrate(). But I don't blame you, because EnsureCreated() is definitely a misleading method name. It does a lot, since it also creates the DB schema that is not even based on migrations, but on the current state of the entities.

But if you don't want to use migrations for Identity context (because you don't extend those entities in any way), then the reverse is true: You don't need to call Migrate(), and calling EnsureCreated() is enough to make sure that the schema is created the first time.

Is calling Migrate() necessary?

As for what's best practice: Some developers don't like to call Migrate() at all from code, because they believe that DB schema operations like that should be more controlled (I'm sure you know that you can execute db update from CLI too). It depends on your requirements I guess.

And with respect to this specific case on having a separate database for Identity tables: They most likely will never change, and they especially won't create a migration by themselves. So I'd say that calling Migrate() on it is unnecessary, besides the fact that it can create and migrate the database if it didn't exist (so it might be useful to keep for that reason; if you're using migrations for that context to begin with).

Detecting whether migration is needed

You can use context.Database.GetPendingMigrationsAsync() to check if migration is needed. How it's done is that the DB has an EFMigrationsHistory table that stores the Id of the applied migrations, which can be compared to the migrations files in your solution.

But I think most developers don't call this GetPendingMigrationsAsync() (or the sync version, for that matter), because you can just call Migrate(), and if the DB is already updated, no harm is done.

Clarifying Migrations vs EnsureCreated

I'm not sure how much have you worked with EF, so chances are this is obvious. But Migrate() is used when you already created migrations with e.g. dotnet ef migrations add <migrationname>, which is a way to incrementally alter the database schema with a code-first approach.

但是,如果您根本不使用迁移,则您有一个非常简单的架构,不需要通过迁移来增量更改,并且您只想确保数据库存在一个架构,然后仅使用 ,EnsureCreated()和不要使用Migrate()

问题是,如果您碰巧更改了实体,EnsureCreated()则不会更新数据库;如果数据库已经存在,则不执行任何操作。因此,您必须EnsureDeleted()随后调用EnsureCreated()才能获得最新的数据库架构而无需迁移。这显然会导致丢失所有数据。这就是迁移有用的原因。EnsureCreated()主要用于集成测试等。


顺便说一句,您可以为自己的表和身份使用相同的数据库上下文;我敢说这是使用 EF 的“正常”方式。当然,我想你可能有分手的具体原因。