繁体   English   中英

EF Core 迁移(代码优先):如何添加新的非空列并使用不基于其他字段数据的唯一值填充现有记录?

[英]EF Core Migration (code first): How do I add a new non-null column and populate existing records with unique values not based on data in other fields?

我目前有一个实体:

迁移前的客户实体

我想添加一个非空字段/列,并且我想用唯一值(例如 GUID)填充每条记录:

迁移后的客户实体

我的困惑是如何用满足 UNIQUE 约束的数据填充现有行。 我可以执行以下迁移之一,但它们都使用相同的 GUID 填充所有现有行:

// OPTION 1

// 😢 Uses same GUID for all rows
migrationBuilder.AddColumn<string>(
    name: "PublicId",
    table: "Customers",
    nullable: false,
    defaultValue: Guid.NewGuid().ToString());

migrationBuilder.CreateIndex(
    name: "IX_Customers_PublicId",
    table: "Customers",
    column: "PublicId",
    unique: true);
// OPTION 2

migrationBuilder.AddColumn<string>(
    name: "PublicId",
    table: "Customers",
    nullable: false,
    defaultValue: "");

// 😢 Still uses same GUID for all rows
migrationBuilder.Sql($"UPDATE Customers SET PublicId = '{Guid.NewGuid()}' WHERE PublicId = ''");

migrationBuilder.CreateIndex(
    name: "IX_Customers_PublicId",
    table: "Customers",
    column: "PublicId",
    unique: true);

是否可以在迁移中做一些事情,用唯一值填充每个现有行?

如果它很重要,引擎盖下的数据库是 SQLite。


更新

我只是以 GUID 为例。 在我的例子中,它是另一个应用程序 function 为这个新字段/列生成唯一 ID。

换句话说,我不能按照数据库(例如NEWID() )为我生成唯一 ID。

您可以使用defaultValueSql设置自定义 SQL 表达式和newid()作为表达式(用于 SQL 服务器)。

migrationBuilder.AddColumn<string>(
  name: "PublicId",
  table: "Customers",
  nullable: false,
  defaultValueSql: "newid()");

Sqlite 应该有类似的东西。

您需要将其添加为可为空,让您的应用程序设置 id,然后将其更改为非 null。

至于你是否可以在单个 EF Core“ApplyMigrations()”过程中做到这一切——我怀疑如果你足够坚定的话。 例如,如果您在应用程序中使用 EF Core 应用迁移,那么这是我想到的一种方法:

  1. 添加两个迁移,第一个添加可为空的列 - 记下它的“MigrationId”。 第二个是空的,也获取它的迁移ID。

// check to see if we need to apply this migration - it may have been applied already on a previous app startup.

 var pendingMigrations = await dbContext.Database.GetPendingMigrationsAsync();
 var applyFirstMigration = IsMigrationIdPending(pendingMigrations, "Your-Migration-Id-That-Adds-Nullable-Column");

// Note that DbContext.Migrate() builds on top of the `IMigrator` service, which can be used for more advanced scenarios. 

var migrator = myDbContext.GetInfrastructure().GetService<IMigrator>();

if(applyFirstMigration)
{
// apply the migrations only up to the one that adds the nullable column
await migrator.MigrateAsync("Your-Migration-Id-That-Adds-Nullable-Column", CancellationToken);

}

var applySecondMigration = IsMigrationIdPending(pendingMigrations, "Your-Migration-Id-That-Does-Nothing");

if(applySecondMigration)
{
// use whatever foo you need to set these records in the database to values provided here by your application - this could be executing a script via ado net, another dbcontext, this dbontext (not sure whether that will work), or even - passing the ids statically (static property) on your "empty" ef core migration, and have that ef core migration generate SQL to execute when it is applied etc)
await UpdateRecordsWithNull();
await migrator.MigrateAsync("Your-Migration-Id-That-Does-Nothing", CancellationToken); // makes sure this migration is applied so we won't ever run this step again.

}


暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM