在代码优先迁移中使用现有行将唯一索引添加到 table 时处理重复项
Handling duplicates when adding unique index to table with existing rows in code first migration
我想使用代码优先迁移向现有 table 添加一个具有唯一索引的新列。因为 table 已经有数据,所以在创建新列时,所有现有行都设置为 NULL。迁移应用失败,因为这违反了新索引的唯一约束。
这是我的迁移:
public override void Up()
{
AddColumn("dbo.SignInToken", "Token", c => c.String(maxLength: 32));
// How can I update existing rows here?
CreateIndex("dbo.SignInToken", "Token", unique: true);
}
错误:
The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'dbo.SignInToken' and the index name 'IX_Token'. The duplicate key value is ().
新列将包含我在代码中设置的随机生成的字符串。
我知道我可以使用 Sql
方法在迁移中执行原始 SQL。我想过使用游标来更新每一行,但随后我将不得不编写一个存储过程来模仿生成随机标记的 C# 方法。我宁愿不必这样做。我想到的另一件事是,如果有一种方法可以检索所有行,我可以循环遍历它们并使用 Sql
方法对每一行执行更新语句,但我不知道这是不是可能。
有没有办法在添加唯一约束之前从迁移中单独更新所有现有行?
一种解决方案是将主键复制到新列中。如果需要,可以在种子方法中更新。
更新迁移:
public override void Up()
{
AddColumn("dbo.SignInToken", "Token", c => c.String(maxLength: 40));
Sql("UPDATE dbo.SignInToken SET Token = Id");
CreateIndex("dbo.SignInToken", "Token", unique: true);
}
然后,如果需要,您可以使用 Seed
方法中的 DbContext
来更新行。需要一些逻辑来确保它不会在未来的迁移中覆盖新数据(例如,仅在 Id == Token
时更新行)。
此外,如果您没有现有的唯一列(复制它的值)并且想要将唯一列添加到已经有一些行的 table 中,您可以尝试这种方法
AddColumn("dbo.SignInToken",
"Token",
c => c.Int(nullable: false,
defaultValueSql: "CONVERT(int, CONVERT(VARBINARY(16), NEWID(), 1))"));
CreateIndex("dbo.IriSqlServerLayer", "Order", unique: true, name: "IX_UniqueOrder");
我想使用代码优先迁移向现有 table 添加一个具有唯一索引的新列。因为 table 已经有数据,所以在创建新列时,所有现有行都设置为 NULL。迁移应用失败,因为这违反了新索引的唯一约束。
这是我的迁移:
public override void Up()
{
AddColumn("dbo.SignInToken", "Token", c => c.String(maxLength: 32));
// How can I update existing rows here?
CreateIndex("dbo.SignInToken", "Token", unique: true);
}
错误:
The CREATE UNIQUE INDEX statement terminated because a duplicate key was found for the object name 'dbo.SignInToken' and the index name 'IX_Token'. The duplicate key value is ().
新列将包含我在代码中设置的随机生成的字符串。
我知道我可以使用 Sql
方法在迁移中执行原始 SQL。我想过使用游标来更新每一行,但随后我将不得不编写一个存储过程来模仿生成随机标记的 C# 方法。我宁愿不必这样做。我想到的另一件事是,如果有一种方法可以检索所有行,我可以循环遍历它们并使用 Sql
方法对每一行执行更新语句,但我不知道这是不是可能。
有没有办法在添加唯一约束之前从迁移中单独更新所有现有行?
一种解决方案是将主键复制到新列中。如果需要,可以在种子方法中更新。
更新迁移:
public override void Up()
{
AddColumn("dbo.SignInToken", "Token", c => c.String(maxLength: 40));
Sql("UPDATE dbo.SignInToken SET Token = Id");
CreateIndex("dbo.SignInToken", "Token", unique: true);
}
然后,如果需要,您可以使用 Seed
方法中的 DbContext
来更新行。需要一些逻辑来确保它不会在未来的迁移中覆盖新数据(例如,仅在 Id == Token
时更新行)。
此外,如果您没有现有的唯一列(复制它的值)并且想要将唯一列添加到已经有一些行的 table 中,您可以尝试这种方法
AddColumn("dbo.SignInToken",
"Token",
c => c.Int(nullable: false,
defaultValueSql: "CONVERT(int, CONVERT(VARBINARY(16), NEWID(), 1))"));
CreateIndex("dbo.IriSqlServerLayer", "Order", unique: true, name: "IX_UniqueOrder");