【问题标题】:Handling duplicates when adding unique index to table with existing rows in code first migration在代码优先迁移中向具有现有行的表添加唯一索引时处理重复项
【发布时间】:2016-07-08 09:50:41
【问题描述】:

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

还有错误:

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

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

我知道我可以使用 Sql 方法在迁移中执行原始 SQL。我曾想过使用游标来更新每一行,但随后我将不得不编写一个存储过程来模仿生成随机标记的 C# 方法。我宁愿不必这样做。我想到的另一件事是,如果有办法检索所有行,我可以遍历它们并使用Sql 方法对每一行执行更新语句,但我不知道这是否可能。

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

【问题讨论】:

    标签: c# sql entity-framework ef-code-first entity-framework-migrations


    【解决方案1】:

    一种解决方案是将主键复制到新列中。如果需要,可以在种子方法中更新它。

    更新迁移:

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

    【讨论】:

    • 这个解决方案对我来说效果很好。实际上,我不需要费心更新我的 Seed 方法中的数据,而是为其他人提供了这些信息。
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-27
      • 1970-01-01
      • 1970-01-01
      • 2018-01-18
      • 1970-01-01
      • 2013-02-27
      • 2014-04-09
      • 1970-01-01
      相关资源
      最近更新 更多