17

バックグラウンド:

長期間の開発で作成された複数の (読み取り ~ 60) 移行を含むを使用するプロジェクトがあります。当然のことながら、これらの移行には次のものも含まれます。

  • 制約の削除12
  • トリガーの作成

走るとすべてがユニコーンと虹

Update-Database

各移行は個別のバッチとして実行されるためです。ただし、SQL Scriptsこれらの移行用に作成する場合は、

Update-Database -Script

以下に説明するように、いくつかの問題が発生しました。

問題 1:

複数の移行ファイルにわたって複数の制約を削除する場合、EF によって生成されたスクリプトは、削除に使用する変数を再宣言する傾向があります。これは、同じ移行ファイル内の変数名の一意性が保証されるためですが、ファイルが変更されると、カウンターがリセットされ、名前が重複するためです。

問題 2:

CREATE TRIGGERSQL は、それが常にバッチ内の最初のステートメントであることを強制します。スクリプトが生成されると、EF は の内容をSql("CREATE TRIGGER ... ");認識しないため、特別に処理しません。したがって、ステートメントがスクリプト ファイルの途中に表示され、エラーが発生する場合があります。

解決策: (または、そう考えた!)

2 つの問題に対する一般的/常識的な解決策は、SQL バッチの Begin/End を適切な場所に挿入することです。手動でこれを行うと、私は非常に金持ちになるので、効率的な解決策ではありません.

代わりに、@DavidSette が提供する手法を使用しました。効果的にオーバーライドする新しいBatchSqlServerMigrationSqlGenerator継承を作成し、機密性の高いステートメントを次のように強制します。SqlServerMigrationSqlGeneratordropColumnOperationsqlOperationGO

protected override void Generate (System.Data.Entity.Migrations.Model.DropColumnOperation dropColumnOperation)
{
    base.Generate(dropColumnOperation);
    Statement("GO");
}

ブーブー:

このソリューションは、次のエラーでフラグUpdate-Databaseなしで実行を中断します。-Script

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

これは、カスタム ジェネレーターによって追加されました。理由は定かではありませんが、EF が認識しないのにはかなりの理由があるはずGOです。

より詳しい情報:

  1. 移行: 2 つの制約を削除するスクリプトで @var0 変数を複製する
  2. 変数名 '@number' は既に宣言されています
  3. MigratorScriptingDecorator によって生成された SQL スクリプトをオーバーライドするにはどうすればよいですか
  4. Entity Framework の移行: -Script 出力のみに Go ステートメントを含める

完全なエラー:

Applying code-based migration: 201205181406363_AddTriggerForOverlap.
GO
System.Data.SqlClient.SqlException (0x80131904): Could not find stored procedure 'GO'.
    at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
    at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
    at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout)
    at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
    at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
    at System.Data.Entity.Migrations.DbMigrator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement)
    at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ExecuteSql(DbTransaction transaction, MigrationStatement migrationStatement)
    at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements)
    at System.Data.Entity.Migrations.Infrastructure.MigratorBase.ExecuteStatements(IEnumerable`1 migrationStatements)
    at System.Data.Entity.Migrations.DbMigrator.ExecuteOperations(String migrationId, XDocument targetModel, IEnumerable`1 operations, Boolean downgrading, Boolean auto)
    at System.Data.Entity.Migrations.DbMigrator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
    at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
    at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
    at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
    at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
    at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
    at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.RunCore()
    at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
ClientConnectionId:ac53af4b-1f9b-4849-a0da-9eb33b836caf
Could not find stored procedure 'GO'.

したがって、基本的にスクリプトを修正すると、重要なコマンドが壊れます。2つの悪のどちらが小さいかを判断するのを手伝ってください!

4

4 に答える 4

2

私は Sql("--<GO>"); を入れました。各移行の最後に。これは、適用された移行として問題なく実行され、SQL をスクリプト化するときに、「--<GO>」から「GO」への検索と置換を行うだけです。少し手動ですが、私にとってはうまくいきます。Sql("--<GO>"); を置くことができます。あなたの作成トリガーステートメントの周り。

于 2013-03-12T16:59:32.640 に答える
1

私が直接問題を経験した後..

小規模な移行を作成することにしました。変更が GO コマンドを必要とするほど大きかった場合、開発者は移行であまりにも多くの変更を試みていました。残念ながら、移行の内容を制御する唯一の方法は、変更をコメント アウトすることです。

また、なぜスクリプトがそんなにひどく欲しかったのか考えてみました。EFが移行を正しく実行することを信頼していなかったわけではありません(最初にテストした場合)。理想的には、私はそれを変更する理由がありません. 私が EF Code First を使い始めたとき、私はそれを数回しか見ていませんでした。

この回答は好きではありませんが、Entity Framework Code First の移行をデバッグする以外の目的には役立たないと思います。

于 2012-11-27T20:17:35.700 に答える
1

msdnによると

「GO は Transact-SQL ステートメントではありません。これは、sqlcmd ユーティリティと osql ユーティリティ、および SQL Server Management Studio コード エディターによって認識されるコマンドです。」

上記のツールのいずれも使用していませんが、SqlCommand クラスを使用して Sql ステートメントを実行しているため、Sql Server (EF ではありません - 例外が発生したスタック トレースを参照してください) が窒息しています。

于 2012-11-27T18:52:59.837 に答える
-1

この行の繰り返しをすべて削除するだけです。

DECLARE @var0 nvarchar(128)

最初の宣言だけで十分です。あなたのスクリプトはスムーズに動作します! :)

于 2013-11-11T04:29:42.580 に答える