2012-07-18 9 views
15

エンティティフレームワークの移行計画の一環として、データの移動をデバッグするために、スクリプトを生成するために-Scriptパラメータを使用することがよくあります。エンティティフレームワークの移行:Goステートメントのみを-Script出力に含める

このスクリプトをクエリアナライザに取り込んで、手動でテストするためにトランザクションでラップすることができました。

私はスクリプトを適切に実行するためにGo文が必要な状況に遭遇しました。 Goを適切な場所に出力するために、次のコードが移行に追加されました。

Sql("GO"); 

-Scriptを使用すると、適切な位置にGO文が追加されます。しかし、-Scriptは使用されません。私は例外を取得します...

System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'. 

スクリプトにGoコマンドを追加する安全な方法はありますか?

+0

なぜGOが必要ですか?これはSQL文ではなく、SQLツールのコマンドです。 –

+0

@ LadislavMrnka - 私はこの疑問の中で完全にもっともらしいユースケースを定義しました(それに関連する問題もあります):http://stackoverflow.com/q/13589986/476786 – bPratik

答えて

7
internal sealed class Configuration : DbMigrationsConfiguration<Context> 
{ 
    public Configuration() 
    { 
     AutomaticMigrationsEnabled = false; 
     const string providerInvariantName = "System.Data.SqlClient"; 
     SetSqlGenerator(providerInvariantName, new BatchingMigrationSqlGenerator(GetSqlGenerator(providerInvariantName))); 
    } 

    protected override void Seed(Context context) 
    { 
    } 

} 

internal class BatchingMigrationSqlGenerator : MigrationSqlGenerator 
{ 
    private readonly MigrationSqlGenerator migrationSqlGenerator; 

    public BatchingMigrationSqlGenerator(MigrationSqlGenerator migrationSqlGenerator) 
    { 
     this.migrationSqlGenerator = migrationSqlGenerator; 
    } 

    public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken) 
    { 
     var migrationStatements = migrationSqlGenerator.Generate(migrationOperations, providerManifestToken).ToArray(); 
     foreach (var migrationStatement in migrationStatements) 
     { 
      migrationStatement.BatchTerminator = "GO"; 
     } 
     return migrationStatements; 
    } 
} 
+0

私はもはやこれをテストする立場にはいませんが、これは私にとってすばらしい解決策のように見えます。私は答えを受け入れています。 –

+0

@BenTaylor私は基本クラスの使用法を提案してもよいでしょうか? 公共オーバーライドのIEnumerable を生成(IEnumerableを migrationOperations、ストリングproviderManifestToken) {foreachの(base.Generateでのvar migrationStatement(migrationOperations、providerManifestToken)) {migrationStatement.BatchTerminator = "GO"。 yield return migrationStatement; } } – regisbsb

+0

アップして申し訳ありません。ストアドプロシージャでは機能しません – regisbsb

13

私は最近まったく同じ状況にぶつかった。私のEFコードの移行では、しばしば新しいテーブルまたは列が導入されます.Sql(...)を使用したデータ移行は、新しいテーブル/列を参照したい場合もあります。あなたが指摘したように、EFコードの移行として実行すると、各ステートメントはDBへの個別のバッチとして発行されるように見え、したがって問題はありません。ただし、本番用のデプロイメントの制約を満たすために、コード・マイグレーションのセットをスプリントから単一スクリプト(-Scriptを使用)に変えて、デプロイメント・チームのための単一のSQLスクリプト・マイグレーションを提示します。このスクリプトファイルは、単一のコードの移行から1つのT SQLバッチを処理しようとしたために、後で説明するバッチで以前に定義された構造を参照しようとしたため、失敗することがあります。

私は特に、私はこれを緩和するために、今のところ撮影したが、ここで彼らは2つのアプローチのどちらか好きではありません。その時点で私が思うようになったら、コードの移行を2つのマイグレーションに分けて、スクリプト化されたときに2つ(またはそれ以上)の別々のバッチになるようにします。コードマイグレーションの開発中にこれが必要であるというフィードバックがなく、エラーが発生しやすいように思われるので、私はこれが好きではありません。

b。私が集計スクリプトを生成するとき、それらをスクラッチDBに対して実行してそれらを証明し、そのスクリプトに必要な箇所に手動で "GO"ステートメントを注入することになります。これは、戻って行かなくてはならない厄介なプロセスであり、コードマイグレーションを100%反映したものではなく、スクリプト出力をもたらします。

EFコードの移行のソースコードをまだ掘り下げておらず、なぜ "GO"をストアドプロシージャとして解釈するのか、ソースコードに何かがあるそれを避けるための指示を与えるための方法に。

+0

少なくとも1人は知ってうれしいですこの問題があります。結局、私はEFの移行をより快適にすることに終わりました。これが問題の解決策です。 –

+0

+1のための提案a。私は戻っていくつかの移行の間に私の変更を分割することができたので、それはスクリプトを編集している(それはProdへのデプロイに必要です)と感じました。ありがとう! – jkoreska

+0

私はこの答えによって慰めと失望しています。私はそれが私だけではないことを知って慰めています、そして、私が見ている問題が本当のものであることには失望しています。 – bwerks

2

-Scriptパラメータの有無にかかわらず移行を実行すると、2つの異なるConfigurationクラスが使用されました。私のConfigurationクラスのうちの1つでは、MigrationSqlGeneratorをカスタム実装にラップし、GOステートメントを追加します。

+2

あなたはこれを例にしていますか? –

0

私が使用してきました:

public class MigrationScriptBuilder : SqlServerMigrationSqlGenerator 
{ 
#if !DEBUG 
    protected override void Generate(System.Data.Entity.Migrations.Model.SqlOperation sqlOperation) 
    { 
     Statement("GO"); 

     base.Generate(sqlOperation); 

     Statement("GO"); 
    } 
#endif 
} 

を、それがデバッグだときに、それはクラッシュしません。そして私はリリースモードからスクリプトを書いています。

0

これは私のために働いている:

(移行プロセスフロー)を使用することができます(他の回答に見られるように)
public class MigrationScriptBuilder : SqlServerMigrationSqlGenerator 
{ 
    public override IEnumerable<MigrationStatement> Generate(IEnumerable<MigrationOperation> migrationOperations, string providerManifestToken) 
    { 
     var statements = base.Generate(migrationOperations, providerManifestToken); 

     statements = statements.SelectMany(s => new[] { 
      s, 
      new MigrationStatement 
      { 
       Sql = "GO" 
      } 
     }).ToList(); 

     return statements; 
    } 
} 

DbContextの構成でこのような方法で:

public Configuration() 
    { 
     SetSqlGenerator("System.Data.SqlClient", new MigrationScriptBuilder()); 
    } 
関連する問題