1

私はEFコードファーストを使用しています。本番データベースの1つのテーブルの主キーのデータ型を変更する必要があります。以上のようにプロダクションDBのプライマリキーのデータ型を変更する

public class Course 
{ 
    [Key] 
    public Guid Id {get; set;} //This needs to be changed to int 

    public string Name {get;set;} 

    public virtual ICollection<Group> Groups {get;set;} 
} 

public class Group 
{ 
    [Key] 
    public Guid Id {get; set;} 

    public string Name {get;set;} 

    public virtual ICollection<Course> Courses{get;set;} 
} 

多対多の関係であり、EFは、Group_IdCourse_Id両方としてPK & FKで自動的にテーブルGroupCoursesを結合作成しました。これまではうまいです。

Courseエンティティの主キーをintからGuidに変更する必要があります。

データ型をGuidからintに変更し、新しい移行を正常に作成しました。しかし、私がコマンドupdate-databaseを実行しようとすると、以下のエラーが発生します。

オペランドタイプ衝突:UNIQUEIDENTIFIERは、私は上記のエラーを修正するかどうかはわからないクエリ

のintと互換性がありません。

また、データを失うことなくプライマリキーフィールドのデータ型を変更することは不可能だと思います(もちろん、バックアップから手動でコピーすることもできます)。私は間違っていると思う。

誰かがデータを失うことなくこれを達成するより良い方法があると教えてください。

注::私は他のSOの投稿や他のインターネットフォーラムを通過しましたが運はありません。

+0

古いCourseテーブルのすべてのデータを 'Seed()'メソッドを使ってTempにアップサンプリングするCourseTempを追加するための移行はできますか?その後、元のコースを削除してCoureseTempクラス/テーブルの名前を変更する別の移行を行うことができますか? – Bwolfing

答えて

1

発生した移行がintegerGuidからタイプを変更するには、影響を受けた列に直接ALTER COLUMN行おうとし、Guid値が暗黙的にinteger値に変換することができないので、それができないため、あなたはタイプの衝突エラーが表示されます。

移行を手動で変更する必要があります。 AlterColumn行を削除します。データ損失なしで既存のコースIDを移行するには、既存のGuid列の名前を変更して(接尾辞_Oldを追加)、正しい新しい名前とタイプの新しい列を作成し、関係テーブルの内容をSELECTUPDATE、そして最終的に古い列を削除:私はコードで私がコメント//Added//Removedで変更された行をマークし

public override void Up() 
{ 
    DropForeignKey("dbo.GroupCourses", "Course_Id", "dbo.Courses"); 
    DropIndex("dbo.GroupCourses", new[] { "Course_Id" }); 
    DropPrimaryKey("dbo.Courses"); 
    DropPrimaryKey("dbo.GroupCourses"); 

    //Removed: AlterColumn("dbo.Courses", "Id", c => c.Int(nullable: false, identity: true)); 
    RenameColumn("dbo.Courses", "Id", "Id_Old"); //Added 
    AddColumn("dbo.Courses", "Id", c => c.Int(nullable: false, identity: true)); //Added 

    //Removed: AlterColumn("dbo.GroupCourses", "Course_Id", c => c.Int(nullable: false)); 
    RenameColumn("dbo.GroupCourses", "Course_Id", "Course_Id_Old"); //Added 
    AddColumn("dbo.GroupCourses", "Course_Id", c => c.Int(nullable: false)); //Added 
    Sql(@"UPDATE gc SET gc.Course_Id = c.Id " 
      + "FROM dbo.GroupCourses as gc " 
      + "INNER JOIN dbo.Courses as c ON gc.Course_Id_Old = c.id_Old"); //Added 

    DropColumn("dbo.GroupCourses", "Course_Id_Old"); //Added 
    DropColumn("dbo.Courses", "Id_Old"); //Added 

    AddPrimaryKey("dbo.Courses", "Id"); 
    AddPrimaryKey("dbo.GroupCourses", new[] { "Group_Id", "Course_Id" }); 
    CreateIndex("dbo.GroupCourses", "Course_Id"); 
    AddForeignKey("dbo.GroupCourses", "Course_Id", "dbo.Courses", "Id", cascadeDelete: true); 
} 

を。残りのコードは、モデル内でプロパティタイプをintに変更した後にAdd-Migrationで生成された移行の元のコードです。

UPDATEの値を記入する必要があるのは、関係テーブルの列の値だけです。 Courses.Id列の値はidentity列であるため、自動生成されます。

また、Down()メソッドを理解して、逆のプロセスを実装するか、実際にデータベースを以前のマイグレーションにダウングレードしない場合はそのまま残しておく必要があります。

また、移行とシーダー間でコードを分割することでこれを行うこともできます。スキーマの変更にはマイグレーションを、データ変更にはシーダーを使用することになっているので、概念的にはより正確です。しかし、この方法は簡単だと思うし、シードアのアプローチでは2つの移行が必要です:UPDATE以外のすべてのコードを含むものと_Oldの列をドロップする文、 _Old列を削除しました。 UPDATE部分はシーダーに実装されます。

警告:UPDATE文に含まれるSQLコードはSql Serverで動作しますが、他のデータベースエンジンでは機能しない可能性があります。シーダーの代わりにマイグレーションを使用することのもう一つの欠点です。

+0

非常に詳細な答え。ありがとう:-) – Venky

+0

ようこそ! – Diana

関連する問題