【问题标题】:EntityFramework Core automatic migrationEntityFramework Core 自动迁移
【发布时间】:2021-03-12 11:29:37
【问题描述】:

在我的项目中,我有 2 个数据库:一个是我的自定义数据库,另一个是 ApplicationDbContext Microsoft 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(),应用程序第一次运行时会创建表,但第二次会引发错误,因为表已存在于数据库中。

【问题讨论】:

  • 您看到了什么具体错误?你在使用 MS SQL 数据库吗?例如,因为某些迁移在 Sqlite 上往往会失败。顺便说一句,EnsureCreated() 不只是创建数据库;它还根据模型的当前状态(忽略迁移)创建整个数据库模式。
  • 我正在使用 MSSQL。我不明白什么时候必须调用迁移。有没有办法检测应用程序是否需要运行迁移?
  • 我更新了答案;希望它有用。随意添加更多问题;我打字很快。 :)
  • 我已经阅读了问题中的更新,但问题很明显。如果数据库已经存在,EnsureCreated 不会做任何事情。当您使用RelationalDatabaseCreator.CreateTables()(顺便说一句,文档明确不建议在应用程序代码中使用)时,它预计数据库中没有表(文档中也提到了)。坦率地说,您遇到这些问题的原因是您以奇怪的方式使用 EF Core。 :) 但是如果你坚持这样使用它,你可能会忽略 CreateTables() 抛出的异常,使用空的 try/catch。
  • 奇怪的方式是什么意思? EF Core 必须在应用程序正常启动时创建表。

标签: asp.net-core entity-framework-core microsoft-identity-web


【解决方案1】:

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

来自docs

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

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

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

有必要拨打Migrate()吗?

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

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

检测是否需要迁移

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

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

澄清迁移与EnsureCreated

我不确定您与 EF 合作了多少,所以这很可能是显而易见的。但是Migrate() 在您已经使用例如创建迁移时使用。 dotnet ef migrations add &lt;migrationname&gt;,这是一种以代码优先的方式逐步更改数据库架构的方法。

但是,如果您根本不使用迁移,那么您有一个非常简单的架构,不需要随着迁移而增量更改,并且您只想确保数据库与架构一起存在,然后使用只用EnsureCreated(),不要用Migrate()

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


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

【讨论】:

  • 这是给Microsoft.Identity的吗?
  • 它不依赖于身份。这些也只是普通 DbContext 中的普通 DbSet。
【解决方案2】:

您不需要同时使用db.Database.EnsureCreated();db.Database.Migrate(); 当您的应用程序中没有启用迁移时,您需要使用db.Database.EnsureCreated();。如果您启用了迁移,那么只使用 db.Database.Migrate(); 就足够了。

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

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

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

【讨论】:

  • 然后,我可以删除迁移文件,禁用迁移并仅使用db.Database.Migrate();。如何禁用迁移?
  • 我认为您的意思是“仅使用 db.Database.EnsureCreated();”。因此,只需从数据库中删除迁移文件和 MigrationHistory 表。就够了
【解决方案3】:

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

dbPSC.Database.EnsureCreated();
if (dbPSC.Database.GetPendingMigrations().Count() > 0)
    dbPSC.Database.Migrate();

【讨论】:

    猜你喜欢
    • 2019-11-21
    • 2021-06-04
    • 2018-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多