2012-06-03 66 views
24

使用代碼優先遷移將新的不可爲空列添加到表中時,它會自動爲您創建默認值。這很有意義,因爲現有行需要爲新列創建一個值(因爲它不能爲空)。這很好,但在此之後,我們不再需要它了。它是不可空的,因爲我想確保總是顯式插入一個值。如果一切默認爲''或0,那麼我會有魔術字符串。無論如何,我可以用一個解決方案來解決問題,我並不感到興奮,但它很有效。先在代碼中添加新列後刪除默認約束

添加列後,我放棄默認約束。

public override void Up() 
{ 
    AddColumn("dbo.SomeTable", "NewColumn", c => c.Int(nullable: false)); 
    Sql(Helpers.DropDefaultConstraint("dbo.SomeTable", "NewColumn")); 
} 

...

public static string DropDefaultConstraint(string table, string column) 
{ 
    return string.Format(@" 
     DECLARE @name sysname 

     SELECT @name = dc.name 
     FROM sys.columns c 
     JOIN sys.default_constraints dc ON dc.object_id = c.default_object_id 
     WHERE c.object_id = OBJECT_ID('{0}') 
     AND c.name = '{1}' 

     IF @name IS NOT NULL 
      EXECUTE ('ALTER TABLE {0} DROP CONSTRAINT ' + @name) 
     ", 
     table, column); 
} 

優點:一旦輔助方法來實現,我只需要添加一個簡單的線條,以刪除約束。 CONS:似乎沒有必要創建一個索引來刪除它。

另一種方法是更改​​生成的遷移,因此我們添加它爲空,更新所有值,然後使其不可空。

public override void Up() 
{ 
    AddColumn("dbo.SomeTable", "NewColumn", c => c.Int()); 
    Sql("UPDATE dbo.SomeTableSET NewColumn= 1"); 
    AlterColumn("dbo.SomeTable", "NewColumn", c => c.Int(nullable: false)); 
} 

優點:簡單,似乎/清潔

缺點:必須暫時改變我的約束(我假設這運行在一個事務,因此,我們不應該讓壞的數據)。大桌子上的更新可能會很慢。

哪種方法更可取?還是有更好的方法,我錯過了?

注意:我已經演示了您一次添加和清理列定義的情況。如果您只是清除先前遷移的默認設置,則第二種方法無效。

+2

解決方案1幫助我刪除了默認約束,謝謝。 – angularsen

+0

這真棒 –

回答

10

就我個人而言,我可以看到第一種方法沒有錯。是的,您必須創建默認約束才能將非空列添加到非空數據集。是的,如果您需要確保新列總是按照您的要求明確添加,那麼您必須在以後刪除它。

即使您仍然有這種方法的問題,問題是,除了你的第二種方法之外,很可能沒有別的選擇。用默認值更新可能較大的表的成本似乎大於創建並立即刪除默認約束的成本。

我可能會考慮稍微修改,雖然我也許可以在SQL約束,以避免仰視發動機指定的默認名稱,像這樣大驚小怪:

Sql("ALTER TABLE tablename 
    ADD columnnametype NOT NULL 
    CONSTRAINT DF_tablename_columnname DEFAULT defaultvalue"); 

(可重寫使用一個輔助功能)

刪除約束則是作爲執行單個ALTER TABLE語句微不足道:

Sql("ALTER TABLE tablename 
    DROP CONSTRAINT DF_tablename_columnname"); 

(同樣,幫手功能很容易在這裏使用。)

但是,這些都可能是一個T-SQL開發人員,我說的比C#更大聲。所以你可能很喜歡你所發佈的例子。

+0

感謝您驗證我的想法。我確實考慮過自己創建約束,但是我更喜歡使用AddColumn,因爲它很容易讀取並且一致,還允許其他一些約束條件,如獨特。我決定堅持選項1.謝謝。 –