2016-03-21 1 views
2

コードの最初の移行を使用して、既存のテーブルに一意のインデックスを持つ新しい列を追加します。テーブルにはすでにデータがあるため、新しい列が作成されると、既存の行はすべて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メソッドを使って各行の更新ステートメントを実行することができますが、これが可能かどうかはわかりません。

ユニーク制約を追加する前に、移行内から既存のすべての行を個別に更新する方法はありますか?

答えて

3

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の場合は行を更新するなど)。すでに既存の一意の列を持っていなかった場合にも

+0

この解決策は私にとってはうまくいきました。私は実際にSeedメソッドでデータを更新する必要はありませんでしたが、他の人にはその情報を含めました。 – Sam

0

(それは値ですコピーする)あなたは、すでにいくつかの行あなたが

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"); 
この方法を試すことができているテーブルに一意の列を追加したいです
関連する問題