1

在我的项目中,我有 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();
}

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

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

使用的最佳做法是什么?是否有必要调用迁移ApplicationDbContext

更新

我已删除该Migration文件夹。然后,改了Startup.cslike

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

    db.Database.EnsureCreated();
    dbPSC.Database.EnsureCreated();
}

但是当应用程序启动时,它根本不会创建任何表。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
}

更新#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();
}

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

4

3 回答 3

3

这个问题很可能是你打电话给EnsureCreated().

文档

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

所以,调用就足够了Migrate()。但我不怪你,因为EnsureCreated()绝对是一个误导性的方法名称。它做了很多,因为它还创建了甚至不是基于迁移,而是基于实体的当前状态的数据库模式。

但是,如果您不想对 Identity 上下文使用迁移(因为您不以任何方式扩展这些实体),那么反之亦然:您不需要调用Migrate(),并且调用EnsureCreated()足以确保架构是第一次创建的。

Migrate()有必要打电话吗?

至于最佳实践是什么:一些开发人员根本不喜欢Migrate()从代码中调用,因为他们认为这样的 DB 模式操作应该受到更多控制(我相信您知道您也可以从 CLI 执行 db update)。我猜这取决于您的要求。

关于为身份表拥有单独数据库的这种特定情况:它们很可能永远不会改变,尤其是它们不会自己创建迁移。所以我会说调用Migrate()它是不必要的,除了它可以创建和迁移数据库(如果它不存在)(因此出于这个原因保留它可能很有用;如果你正在为该上下文使用迁移开始)。

检测是否需要迁移

您可以使用context.Database.GetPendingMigrationsAsync()来检查是否需要迁移。它是如何完成的,数据库有一个EFMigrationsHistory存储应用迁移的 Id 的表,可以将其与解决方案中的迁移文件进行比较。

但我认为大多数开发人员不会调用它GetPendingMigrationsAsync()(或同步版本,就此而言),因为您可以调用Migrate(),如果数据库已经更新,则不会造成任何伤害。

澄清迁移与EnsureCreated

我不确定您与 EF 合作了多少,所以这很明显。但是Migrate()在您已经使用 eg 创建迁移时使用dotnet ef migrations add <migrationname>,这是一种使用代码优先方法增量更改数据库模式的方法。

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

问题是,如果您碰巧更改了实体,EnsureCreated()则不会更新数据库;如果数据库已经存在,它什么也不做。因此,您必须先调用EnsureDeleted(),然后EnsureCreated()才能在没有迁移的情况下实现最新的数据库模式。这显然涉及丢失所有数据。这就是迁移有用的原因。EnsureCreated()主要用于例如集成测试。


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

于 2021-03-12T11:50:48.107 回答
1

您不需要同时使用两者 db.Database.EnsureCreated();,并且db.Database.Migrate(); 您需要db.Database.EnsureCreated();在应用程序中未启用迁移时使用。如果您启用了迁移,那么只使用db.Database.Migrate();就足够了。

但是,如果您不启用迁移,那么在每次更改时您都必须重新创建数据库。因为“EnsureCreated”只验证数据库是否已经存在。所以最好启用迁移。

因此,如果您不想更改 ApplicationDbContext 中的任何内容以便您可以使用db.Database.EnsureCreated();,但如果您想更改某些内容或者您可能想在 AspNetUsers 等中添加更多字段,那么您应该启用迁移并使用db.Database.Migrate();

顺便说一句,如果需要,您还可以在 ApplicationDbContext 中添加自定义表。

于 2021-03-12T12:06:42.600 回答
0

根据你们发给我的回复,我的解决方案是使用迁移。在Startup.cs我添加了那些代码行(dbPSC is a DbContext

dbPSC.Database.EnsureCreated();
if (dbPSC.Database.GetPendingMigrations().Count() > 0)
    dbPSC.Database.Migrate();
于 2021-03-14T20:32:25.937 回答