ビジネスロジックにより、テーブルに新しい列が常に必要であることを確認することが重要です。したがって、NOT NULL
としてテーブルに追加する必要があります。これを行う方法を説明する 前の質問 とは異なり手動で、これはSSDTパブリッシュで管理する必要があります。
いくつかの実現のため、私はしばらくの間、この単純なサウンドのタスクに対して壁に頭をぶつけてきました。
他の人から聞いたアプローチは、テーブル定義を直接更新して(スキーマの更新が一貫するようにする)、コンテンツ全体を移動するデプロイ前スクリプトを書くことです新しい列作成ロジックが含まれる一時テーブルにテーブルを変換し、展開後のスクリプトで行を戻します。ただし、これは非常に危険なようですが、NOT NULL列が既存のデータを含むテーブルに追加されていることを検出すると、発行プレビューが失敗します(展開前スクリプトの前に検証が実行されるため)。
孤立したデータを危険にさらすことなく、またはnullを使用できない新しい列を追加したり、本質的に危険な長い移行スクリプトを使用してすべてのパブリッシュでデータを前後に移動したりするにはどうすればよいですか?
ありがとう。
過去にこれを行った方法を紹介します。これは、2番目のポイントで呼び出す展開前スクリプトの特定の制限を解決するように設計されています。
配置前スクリプトに列を追加すると、同じ列を2回目に自動的に作成しようとしたときにパブリッシュが失敗します(配置前スクリプトがべき等になるように記述されている場合でも)。
SSDTプロジェクトをデプロイすると、プロジェクトをつなぎ合わせる方法は次のようになります(少し簡略化されていますが、一般的には)。
ターゲットデータベースではなくdacpacに新しい列が存在する場合、手順2でその列を追加するコードが生成されます。そのため、配置前スクリプトがこの列を追加すると、スクリプトの主要部分は失敗します(手順1のスキーマ比較の結果に基づいて、列が存在しないと想定しているため)。
マーティン・スミスはこのオプションについてコメントで述べていますが、これが今のところ私にとって最も効果的な解決策です。
供給パイプラインでモデル前スクリプトを使用します。これはSSDTの一部ではなく、dacfxの発行前に実行されるステップです。そのため、この場合、プレモデルスクリプトは列に目的の値を追加してnullにしないようにすることができ、パブリッシュが発生するときはSSDTが予期する状態にあるため、何もする必要がありません。私はまだpredeployスクリプトの多くの用途を見つけていません。 – Martin Smith6月1日21:45
このソリューションを実装する一般的な手順は次のとおりです。
最終的に、これにより、SSDT以前のスクリプトで、複雑なビジネスロジックを使用して入力された任意のカスタムコードを使用して列を追加できます。
SSDTプロジェクトに列定義を追加することもできます(ソース管理はデータベースの実際の状態と一致します)。ただし、スキーマ比較を実行しても、その列に関連する変更は確認されません(既に展開しているため)。
SSDTが完全に不要な場合にSSDTが「テーブルの再構築」操作*を実行する展開をテストすると、よくわかります。これは、更新されたスキーマで新しいテーブルが作成され、すべてのデータがそのテーブルにコピーされ、古いテーブルが削除され、新しいテーブルの名前が変更されて古いテーブルが置き換えられる場所です。
これは、テーブルが大きい場合、大規模なトランザクションログファイルの増大やその他の問題を引き起こす可能性があります。スキーマの変更がこれを引き起こしていることに気付いた場合は、代わりにpre-SSDT(通常は単純なALTER TABLE
ステートメント)、テーブルの再構築を避けます。
私はそう思う。 データベースを提供するための2つの異なるアプローチを批評する:移行と状態 Alex Yatesによると、これは基本的に2つのアプローチを少し組み合わせたものです。 SSDTは状態ベースですが、SSDTが一般的な方法で処理する方法がない複雑なシナリオの一部を処理するために、移行ステップ(SSDTの前)を組み込んでいます。
この回答を書きながら検索を行う場合、何を検索するかがわかったら、これは実際にはSSDTユーザーコミュニティで議論される非常に一般的なアプローチです。私はそれが呼ばれるのを見ました:
等ここに私が上で述べた多くのポイントをカバーする素晴らしい記事があります:
そして、(#4 –システムタイプからユーザー定義タイプセクションへの変更)のRed Gateからの1つで、これも事前比較と呼ばれます。
ReadyRollの有無にかかわらず、10個のSSDT展開障害を修正する方法
Martinは、「デプロイ前スクリプトの多くの使用法」を見つけられなかったと指摘し、私も同じように感じる傾向があります。しかし、それらが役立つシナリオがあります。
同僚が私に指摘した1つの例は、展開後のスクリプトで使用する一時テーブルにデータを格納することでした(たとえば、あるテーブルから別のテーブルに列を移動しているとします)。
*テーブルの再構築は次のようになります。これは恐ろしいことですよね?
GO
PRINT N'Starting rebuilding table [dbo].[MyTable]...';
GO
BEGIN TRANSACTION;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SET XACT_ABORT ON;
CREATE TABLE [dbo].[tmp_ms_xx_MyTable] (
[Id] BIGINT IDENTITY (1, 1) NOT NULL,
-- etc, other columns
);
IF EXISTS (SELECT TOP 1 1
FROM [dbo].[MyTable])
BEGIN
SET IDENTITY_INSERT [dbo].[tmp_ms_xx_MyTable] ON;
INSERT INTO [dbo].[tmp_ms_xx_MyTable] ([Id], ...)
SELECT [Id],
-- etc, other columns
FROM [dbo].[MyTable]
ORDER BY [Id] ASC;
SET IDENTITY_INSERT [dbo].[tmp_ms_xx_MyTable] OFF;
END
DROP TABLE [dbo].[MyTable];
EXECUTE sp_rename N'[dbo].[tmp_ms_xx_MyTable]', N'MyTable';
COMMIT TRANSACTION;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;