2013-02-12 98 views
29

我是EF5 Code First的新手,在開始工作之前,我正在修改概念驗證。EF5代碼優先 - 遷移列類型

我已初步建立,看上去像

public class Person { 
    public int Id { get; set; } 
    public string FirstName { get; set;} 
    public string Surname {get;set;} 
    public string Location {get;set;} 
} 

模型,並利用我有點MVC應用程序,我貼在上面添加幾個記錄。

現在我想的位置列更改爲枚舉,是這樣的:

public class Person { 
    public int Id { get; set; } 
    public string FirstName { get; set;} 
    public string Surname {get;set;} 
    public Locations Location {get;set;} 
} 

public enum Locations { 
    London = 1, 
    Edinburgh = 2, 
    Cardiff = 3 
} 

當我添加新的遷移,我得到:

AlterColumn("dbo.People", "Location", c => c.Int(nullable: false)); 

但是當我運行更新數據庫I得到一個錯誤

Conversion failed when converting the nvarchar value 'London' to data type int. 

在運行alter語句之前,遷移中是否有方法來截斷表?

我知道我可以打開數據庫並手動執行它,但有沒有更智能的方法?

+2

我建議在他們看到如果轉換是自動實體框架下一些此頁面上的答案之前處理過類似的崗位開發。例如,我發現它處理字符串和小數之間的轉換,然後再次返回,沒有我的幫助 - 添加遷移生成的遷移工作正常。顯然,在將其應用於生產之前,先在本地/測試數據庫上嘗試一下。 – pipedreambomb 2016-12-19 14:33:14

回答

45

最聰明的方式可能不會改變類型。如果你需要做到這一點,我建議你做以下步驟:

  1. 添加一個新列與新型
  2. 使用Sql()接管從原來的列中的數據使用的更新語句
  3. 刪除舊列
  4. 重命名新列

這都可以在相同的遷移來完成,正確的SQL腳本將被創建。如果您希望丟棄數據,則可以跳過第2步。如果你想接管它,添加適當的語句(也可以包含一個switch語句)。

不幸的是,Code First Migrations不提供更簡單的方法來完成此操作。

下面是示例代碼:基於@ JustAnotherUserYouMayKnow的回答

AddColumn("dbo.People", "LocationTmp", c => c.Int(nullable: false)); 
Sql(@" 
    UPDATE dbp.People 
    SET LocationTmp = 
     CASE Location 
      WHEN 'London' THEN 1 
      WHEN 'Edinburgh' THEN 2 
      WHEN 'Cardiff' THEN 3 
      ELSE 0 
     END 
    "); 
DropColumn("dbo.People", "Location"); 
RenameColumn("dbo.People", "LocationTmp", "Location"); 
+0

快速提示:使用臨時列是我在遷移'Down()'時發現的唯一方法。模式更新似乎在包含'Sql()'命令的事務中運行,因爲從'Integer'值返回到'String'的列更新失敗並顯示相同的錯誤消息 - 這次在'Sql() '而不是'AlterColumn()'。即使我們在'AlterColumn()'後面運行'Sql()'。 – InteXX 2018-02-03 03:08:38

12

,但更容易。

儘量先執行Sql()命令,然後AlterColumn()

Sql(@" 
    UPDATE dbo.People 
    SET Location = 
     CASE Location 
      WHEN 'London' THEN 1 
      WHEN 'Edinburgh' THEN 2 
      WHEN 'Cardiff' THEN 3 
      ELSE 0 
     END 
    "); 
AlterColumn("dbo.People", "Location", c => c.Int(nullable: false)); 
+1

我比標記的答案更喜歡它:它不需要臨時列。 – Marcel 2017-03-28 13:30:08