C# 在代码第一次迁移中将唯一索引添加到具有现有行的表时处理重复项

C# 在代码第一次迁移中将唯一索引添加到具有现有行的表时处理重复项,c#,sql,entity-framework,ef-code-first,entity-framework-migrations,C#,Sql,Entity Framework,Ef Code First,Entity Framework Migrations,我想使用代码优先迁移将具有唯一索引的新列添加到现有表中。因为表已经有数据,所以在创建新列时,所有现有行都被设置为NULL。迁移无法应用,因为这违反了新索引的唯一约束 以下是我的迁移: public override void Up() { AddColumn("dbo.SignInToken", "Token", c => c.String(maxLength: 32)); // How can I update existing rows here? Create

我想使用代码优先迁移将具有唯一索引的新列添加到现有表中。因为表已经有数据,所以在创建新列时,所有现有行都被设置为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);
}
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);
}
错误是:

CREATE UNIQUE INDEX语句终止,因为为对象名“dbo.SignInToken”和索引名“IX_Token”找到了重复的键。重复的键值为()

新列将包含我在代码中设置的随机生成的字符串

我知道我可以使用
Sql
方法在迁移中执行原始Sql。我曾想过使用游标来更新每一行,但随后我必须编写一个存储过程来模拟生成随机令牌的C#方法。我宁愿不这样做。我想到的另一件事是,如果有一种方法可以检索所有的行,我可以使用
Sql
方法循环它们并在每一行上执行update语句,但我不知道这是否可行


在添加唯一约束之前,是否有办法从迁移中单独更新所有现有行?

一种解决方案是将主键复制到新列中。然后,如果需要,可以在seed方法中对其进行更新

更新的迁移:

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);
}
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
时才更新行)。

同样,如果您没有已经存在的唯一列(要复制它的值),并且要向已经有一些行的表中添加唯一列,您可以尝试这种方法

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");

这个解决方案对我很有效。实际上,我不需要费心更新Seed方法中的数据,而是将这些信息包含在其他方法中。