2012-06-07 18 views
6

使用實體框架4.3.1首先編碼和數據遷移。如何覆蓋由MigratorScriptingDecorator生成的SQL腳本

我已經編寫了一個實用程序,使用MigratorScriptingDecorator爲目標數據庫自動生成遷移腳本。

但是,有時從零開始重新生成目標數據庫時,生成的腳本無效,因爲它會同時聲明兩次具有相同名稱的變量。

變量名稱是@ var0

當應用多個遷移並且至少有兩個導致刪除默認約束時,會出現這種情況。

將出現問題都生成腳本形式的代碼時,以及使用該包管理控制檯命令時:

Update-Database -Script 

下面是有問題的片段形式生成的腳本:

DECLARE @var0 nvarchar(128) 
SELECT @var0 = name 
FROM sys.default_constraints 
WHERE parent_object_id = object_id(N'SomeTableName') 

DECLARE @var0 nvarchar(128) 
SELECT @var0 = name 
FROM sys.default_constraints 
WHERE parent_object_id = object_id(N'SomeOtherTableName') 

我想能夠覆蓋它的地點整理每個遷移的SQL,然後添加一個「GO」語句,以便每個遷移都在單獨的批處理中,這可以解決問題。

任何人有任何想法如何做到這一點,或者如果我吠叫錯誤的樹,那麼也許你可以建議一個更好的方法?

回答

4

因此,大量使用ILSpythe answer to this question中的一些指針,我找到了一種方法。

下面詳細介紹那些感興趣的人。

問題

SqlServerMigrationSqlGenerator是類最終用於創建開始使用的軟件包管理器控制檯-Script開關或使用MigratorScriptingDecorator當時對目標數據庫執行或編寫而成的SQL語句負責。

巷道

檢查在SqlServerMigrationSqlGenerator負責一個DROP COLUMN的Genearate方法,它看起來像這樣:

protected virtual void Generate(DropColumnOperation dropColumnOperation) 
{ 
    RuntimeFailureMethods 
     .Requires(dropColumnOperation != null, null, "dropColumnOperation != null"); 
    using (IndentedTextWriter indentedTextWriter = 
     SqlServerMigrationSqlGenerator.Writer()) 
    { 
     string value = "@var" + this._variableCounter++; 
     indentedTextWriter.Write("DECLARE "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(" nvarchar(128)"); 
     indentedTextWriter.Write("SELECT "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(" = name"); 
     indentedTextWriter.WriteLine("FROM sys.default_constraints"); 
     indentedTextWriter.Write("WHERE parent_object_id = object_id(N'"); 
     indentedTextWriter.Write(dropColumnOperation.Table); 
     indentedTextWriter.WriteLine("')"); 
     indentedTextWriter.Write("AND col_name(parent_object_id, 
                 parent_column_id) = '"); 
     indentedTextWriter.Write(dropColumnOperation.Name); 
     indentedTextWriter.WriteLine("';"); 
     indentedTextWriter.Write("IF "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(" IS NOT NULL"); 
     indentedTextWriter.Indent++; 
     indentedTextWriter.Write("EXECUTE('ALTER TABLE "); 
     indentedTextWriter.Write(this.Name(dropColumnOperation.Table)); 
     indentedTextWriter.Write(" DROP CONSTRAINT ' + "); 
     indentedTextWriter.Write(value); 
     indentedTextWriter.WriteLine(")"); 
     indentedTextWriter.Indent--; 
     indentedTextWriter.Write("ALTER TABLE "); 
     indentedTextWriter.Write(this.Name(dropColumnOperation.Table)); 
     indentedTextWriter.Write(" DROP COLUMN "); 
     indentedTextWriter.Write(this.Quote(dropColumnOperation.Name)); 
     this.Statement(indentedTextWriter); 
    } 
} 

你可以看到它記錄所使用的變量名,但這似乎只能在一批中追蹤,即單個遷移。因此,如果migratin包含多個DROP COLUM上述工作正常,但如果有兩個遷移導致生成DROP COLUMN,則重置_variableCounter變量。

當不生成腳本時沒有遇到任何問題,因爲每個語句都是針對數據庫立即執行的(我使用SQL Profiler進行檢查)。

如果您生成一個SQL腳本並希望儘管您有問題仍按原樣運行它。

解決方案

我創建了一個新的BatchSqlServerMigrationSqlGeneratorSqlServerMigrationSqlGenerator繼承如下(注意,你需要using System.Data.Entity.Migrations.Sql;):

public class BatchSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator 
{ 
    protected override void Generate 
     (System.Data.Entity.Migrations.Model.DropColumnOperation dropColumnOperation) 
    { 
     base.Generate(dropColumnOperation); 

     Statement("GO"); 
    } 
} 

我們強制遷移到使用自定義生成器,你有兩個選擇:

  1. 如果你想要它被整合到t他包管理器控制檯,下面的行添加到您的Configuration類:

    SetSqlGenerator("System.Data.SqlClient", 
            new BatchSqlServerMigrationSqlGenerator()); 
    
  2. 如果你從生成代碼腳本(像我),相似的代碼行添加到你有你的配置組裝在代碼:

    migrationsConfiguration.SetSqlGenerator(DataProviderInvariantName, 
            new BatchSqlServerMigrationSqlGenerator()); 
    
+0

你覺得類似的解決方法可能爲正常的直表插入生成的SQL可能嗎? –