1

我正在使用EF代碼優先。我需要更改生產數據庫中一個表的主鍵的數據類型。更改生產數據庫中的主鍵數據類型

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創建了一個連接表GroupCourses與PK & FK既是Group_IdCourse_Id自動。到現在爲止是好的。

現在我需要將Course實體中的主鍵從Guid更改爲int

我將數據類型從Guid更改爲int併成功創建了新的遷移。但是當我嘗試運行命令update-database時,我得到了錯誤。

操作數類型衝突:唯一標識符是查詢

與詮釋不相容我不知道如何解決上述錯誤。

另外,我認爲不可能在不丟失數據的情況下更改主鍵字段的數據類型(當然,我們可以手動從備份中複製)。我希望我錯了。

有人可以告訴我有沒有更好的方式來實現這一點,而不會丟失數據?

注意:我已經通過其他SO職位相關和其他互聯網論壇,但沒有運氣。

+0

您可以通過'Seed()'方法進行遷移以添加一個CourseTemp,它將您的舊課程表中的所有數據插入到Temp中?那麼你可以做另一次遷移來刪除原始課程並重命名CoureseTemp類/表? – Bwolfing

回答

1

你得到的類型衝突錯誤,因爲產生的遷移嘗試直接ALTER COLUMN做對受影響的列的類型更改從Guidinteger,這是不可能的,因爲Guid值不能隱式轉換爲integer值。

您必須手動修改您的遷移。刪除AlterColumn行。爲了在不丟失數據的情況下遷移現有的課程標識,您可以暫時重命名現有的Guid列(添加後綴_Old),使用正確的新名稱和類型創建新列,並使用正確的值填充關係表中的內容UPDATESELECT,最後刪除舊的列:

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

標誌着我在我的代碼與意見//Added//Removed改變了線路。其餘代碼是在模型中將屬性類型更改爲int後使用Add-Migration生成的遷移中的原始代碼。您只需填寫UPDATE關係表中列中的值。 Courses.Id列中的值將自動生成,因爲它是identity列。

您還應該計算Down()方法並實施相反的過程,或者如果您真的永遠不會將數據庫降級到先前的遷移,就會保持原樣。

您也可以通過拆分遷移和播種機之間的代碼來實現此目的。從概念上講,它會更加正確,因爲您應該使用遷移進行架構修改,並使用播種器進行數據修改。但是我認爲這樣更容易,只需要一次遷移,而使用播種器的方法則需要兩次遷移:一次包含上述代碼,除了UPDATE和刪除_Old列的句子,以及另一個刪除_Old列。 UPDATE部分將在播種機中實施。

警告:UPDATE語句中包含的SQL代碼與Sql Server一起使用,但可能無法與其他數據庫引擎一起使用。這是使用遷移而不是播種機的另一個缺點。

+0

非常詳細的答案。謝謝:-) – Venky

+0

不客氣! – Diana