データベースの開発と配置のための戦略 (C#)
データ ドリブン アプリケーションを初めてデプロイするときは、開発環境のデータベースを検討せずに運用環境にコピーできます。 しかし、後続のデプロイで検討せずにコピーを実行すると、運用データベースに入力されたすべてのデータが上書きされます。 そうしないで、開発データベースに対して前回のデプロイ以降に行われた変更を運用データベースに適用する作業を、データベースのデプロイ作業に含めます。 このチュートリアルでは、これらの課題について詳細に検討し、前回のデプロイ以降に行われた変更の記録とデータベースへの適用を支援するさまざまな戦略を提案します。
はじめに
前のチュートリアルで説明したように、ASP.NET アプリケーションをデプロイするには、該当する内容を開発環境から運用環境にコピーする必要があります。 デプロイは 1 回限りのイベントではなく、新しいバージョンのソフトウェアがリリースされるたびに、またはバグやセキュリティ上の懸念が特定されて対処されるときに発生します。 ASP.NET ページ、イメージ、JavaScript ファイル、その他のファイルを運用環境にコピーするときは、これらのファイルが前回のデプロイ以降にどのように変更されたかについて気にする必要はありません。 ファイルを検討せずに運用環境にコピーして、既存の内容を上書きできます。 残念ながら、このシンプルさはデータベースのデプロイには提供されません。
データ ドリブン アプリケーションを初めてデプロイするときは、開発環境のデータベースを検討せずに運用環境にコピーできます。 しかし、後続のデプロイで検討せずにコピーを実行すると、運用データベースに入力されたすべてのデータが上書きされます。 そうしないで、開発データベースに対して前回のデプロイ以降に行われた "変更" を運用データベースに適用する作業を、データベースのデプロイ作業に含めます。 このチュートリアルでは、これらの課題について詳細に検討し、前回のデプロイ以降に行われた変更の記録とデータベースへの適用を支援するさまざまな戦略を提案します。
データベースのデプロイに関する課題
データ ドリブン アプリケーションが初めてデプロイされる前は、存在する唯一のデータベースが開発環境のデータベースです。そのため、データ ドリブン アプリケーションを初めてデプロイするときに、開発環境のデータベースを検討せずに運用環境にコピーできます。 しかし、アプリケーションがデプロイされると、データベースのコピーは、開発環境に 1 つと、運用環境に 1 つの 2 つになります。
デプロイ間で、開発データベースと運用データベースが同期しなくなる可能性があります。運用データベースのスキーマは変更されませんが、開発データベースのスキーマは、新しい機能の追加に従って変更される可能性があります。 列、テーブル、ビュー、またはストアド プロシージャを追加または削除することがあります。 開発データベースに重要なデータが追加されることもあります。 多くのデータ ドリブン アプリケーションには、ハードコーディングされたアプリケーション固有のデータが設定された、ユーザーが編集できない参照テーブルが含まれています。 たとえば、オークション Web サイトには、オークション対象のアイテムの状態 (新品、新品同様、良品、可) を示すドロップダウン リストが存在する場合があります。 これらのオプションをドロップダウン リストに直接ハードコーディングするのではなく、データベース テーブルに配置することを通常お勧めします。 開発中に、「不良」という名前の新しい状態がテーブルに追加された場合、アプリケーションをデプロイするときに、この同じレコードを運用データベースの参照テーブルに追加する必要があります。
データベースのデプロイ作業に、開発環境から運用環境へのデータベースのコピー作業を含めることが理想的です。 しかし、留意する必要があるのは、アプリケーションをデプロイして開発を再開した後は、運用データベースに実際のユーザーからの実際のデータが設定されていることです。 そのため、次回のデプロイで開発環境から運用環境にデータベースを単純にコピーすると、運用データベースが上書きされて、既存のデータが失われます。 最終結果として、データベースのデプロイ作業とは、前回のデプロイ以降に開発データベースに対して行われた変更の適用になります。
データベースのデプロイにはスキーマと、おそらく前回のデプロイ以降のデータの変更を適用する作業が含まれるため、それらの変更を運用環境に適用できるように、変更履歴を保守する (またはデプロイ時に判断する) 必要があります。 データ モデルに対する変更の管理と適用には、さまざまな手法があります。
ベースラインを定義する
アプリケーションのデータベースに対する変更を保守するには、何らかの開始状態 (変更を適用するベースライン) が必要です。 極端な例として、開始状態を、テーブル、ビュー、ストアド プロシージャのない空のデータベースにできます。 このようなベースラインでは、変更ログに、データベースのすべてのテーブル、ビュー、ストアド プロシージャの作成と、初回のデプロイ後に行われた変更を含める必要があるため、変更ログが大きくなります。 正反対の例として、ベースラインを、初回に運用環境にデプロイされたデータベースのバージョンに設定できます。 このように選択すると、変更ログに、最初のデプロイ後にデータベースに加えられた変更のみが含まれるため、変更ログが大幅に小さくなります。 これはお勧めのアプローチです。 もちろん、より中間的なアプローチを選択して、ベースラインを、データベースの初回の作成とデータベースの最初のデプロイの間の時点に定義できます。
ベースラインを選択したら、ベースライン バージョンを再作成するために実行できる SQL スクリプトを生成することを検討してください。 このようなスクリプトを使用すると、データベースのベースライン バージョンをすばやく再作成できます。 この機能は、大規模なプロジェクトで特に役立ちます。そのようなプロジェクトでは、作業している開発者が複数存在するか、テストやステージングなどの追加の環境が存在する場合があり、それぞれが独自のデータベースのコピーを必要とします。
ベースライン バージョンの SQL スクリプトを生成するために自由に使用できるさまざまなツールがあります。 SQL Server Management Studio (SSMS) で、データベースを右クリックし、[タスク] サブメニューに移動して、[スクリプトの生成] オプションを選択できます。 これによりスクリプト ウィザードが起動し、データベースのオブジェクトを作成するための SQL コマンドを含むファイルを生成するように指示できます。 もう 1 つのオプションは Database Publishing Wizard です。このウィザードは、データベース スキーマだけでなく、データベース テーブル内のデータも作成する SQL コマンドを生成できます。 Database Publishing Wizard については、「データベースの配置」チュートリアルで詳細に検討しました。 使用するツールが何であっても、必要になった場合にデータベースのベースライン バージョンを再作成するために使用できるスクリプト ファイルが最終的に必要です。
普通の文章でデータベースの変更を文書化する
開発フェーズ中にデータ モデルに対する変更のログを保守する最も簡単な方法は、普通の文章で変更を記録することです。 たとえば、既にデプロイされているアプリケーションの開発中に、Employees
テーブルに新しい列を追加し、Orders
テーブルから列を削除し、新しいテーブル (ProductCategories
) を追加する場合は、次の履歴を含むテキスト ファイルまたは Microsoft Word 文書を保守します。
変更日 | 変更の詳細 |
---|---|
2009-02-03: | Employees テーブルに列 DepartmentID (int 、NULL 以外) を追加しました。 Departments.DepartmentID から Employees.DepartmentID への外部キー制約を追加しました。 |
2009-02-05: | Orders テーブルから列 TotalWeight を削除しました。 データは、関連付けられている OrderDetails レコードに既にキャプチャされています。 |
2009-02-12: | ProductCategories テーブルを作成しました。 ProductCategoryID (int 、IDENTITY 、NOT NULL )、CategoryName (nvarchar(50) 、NOT NULL )、Active (bit 、NOT NULL ) の 3 つの列があります。 ProductCategoryID に主キー制約を、Active に既定値 1 を追加しました。 |
この方法にはいくつかの欠点があります。 まず、自動化は期待できません。 これらの変更をデータベースに適用する必要があるとき (アプリケーションのデプロイ時など) はいつでも、開発者が各変更を一度に 1 つずつ手動で実装する必要があります。 さらに、変更ログを使用してベースラインから特定のバージョンのデータベースを再構築する必要がある場合、ログのサイズが大きくなるにつれて、その実行にかかる時間が長くなります。 この方法のもう 1 つの欠点は、各変更ログ エントリの明確さと詳細レベルが、変更を記録する個人に委ねられるということです。 複数の開発者がいるチームでは、作成するエントリの詳細度、読みやすさ、正確さが開発者によって異なることがあります。 入力ミスやその他の人為的なデータ入力エラーも発生する可能性があります。
普通の文章でデータベースの変更を文書化する主な利点は、シンプルさです。 データベース オブジェクトを作成および変更するための SQL 構文に精通している必要はありません。 代わりに、変更を普通の文章で記録し、SQL Server Management Studio のグラフィカル ユーザー インターフェイスを使用して実装できます。
変更ログを普通の文章で保守することは、確かにあまり洗練されていないし、スコープが大きいプロジェクト、データ モデルに頻繁に変更を加えるプロジェクト、複数の開発者が関与するプロジェクトなどの、特定のプロジェクトでは適切に機能しません。 しかし、データ モデルにたまに変更が発生するだけで、唯一の開発者にデータベース オブジェクトを作成および変更するための SQL 構文の強力な経歴がない小さな個人プロジェクトでは、かなり適切に機能するのを見てきました。
Note
変更ログの情報は技術的にはデプロイ時までしか必要ではありませんが、変更の履歴を保持することをお勧めします。 しかし、増量が続く単一の変更ログ ファイルを保守するのではなく、データベースのバージョンごとに異なる変更ログ ファイルを用意することを検討してください。 通常は、データベースをデプロイするたびにそのバージョンが変わります。 変更ログを保守すると、ベースラインに対してバージョン 1 以降の変更ログ スクリプトを、再作成する必要があるバージョンに達するまで実行して、任意のデータベース バージョンを再作成できます。
SQL 変更ステートメントを記録する
普通の文章による変更ログの保守の主な欠点は、自動化の欠如です。 デプロイ時にデータベースの変更を運用データベースに実装する作業は、一連の指示を手動で実行する必要がなく、スクリプトを実行するボタンをクリックするという簡単な作業であることが理想的です。 このような自動化は、データ モデルの変更に使用される SQL コマンドを含む変更ログを保守することで可能になります。
SQL 構文には、さまざまなデータベース オブジェクトを作成および変更するためのいくつかのステートメントが含まれています。 たとえば、"CREATE TABLE ステートメント" を実行すると、指定した列と制約を持つ新しいテーブルが作成されます。 "ALTER TABLE ステートメント" は、既存のテーブルを変更し、その列または制約を追加、削除、または変更します。 インデックス、ビュー、ユーザー定義関数、ストアド プロシージャ、トリガー、その他のデータベース オブジェクトを作成、変更、および削除するステートメントもあります。
前の例に戻ります。既にデプロイされているアプリケーションの開発中に、Employees
テーブルに新しい列を追加し、Orders
テーブルから列を削除し、新しいテーブル (ProductCategories
) を追加するとします。 このようなアクションにより、次の SQL コマンドを含む変更ログ ファイルが生成されます。
-- Add the DepartmentID column
ALTER TABLE [Employees] ADD [DepartmentID]
int NOT NULL
-- Add a foreign key constraint between Departments.DepartmentID and Employees.DepartmentID
ALTER TABLE [Employees] ADD
CONSTRAINT [FK_Departments_DepartmentID]
FOREIGN
KEY ([DepartmentID])
REFERENCES
[Departments] ([DepartmentID])
-- Remove TotalWeight column from Orders
ALTER TABLE [Orders] DROP COLUMN
[TotalWeight]
-- Create the ProductCategories table
CREATE TABLE [ProductCategories]
(
[ProductCategoryID]
int IDENTITY(1,1) NOT NULL,
[CategoryName]
nvarchar(50) NOT NULL,
[Active]
bit NOT NULL CONSTRAINT [DF_ProductCategories_Active] DEFAULT
((1)),
CONSTRAINT
[PK_ProductCategories] PRIMARY KEY CLUSTERED ( [ProductCategoryID])
)
デプロイ時にこれらの変更を運用データベースにプッシュする操作は、ワンクリックです。SQL Server Management Studio を開き、運用データベースに接続し、新しいクエリ ウィンドウを開き、変更ログの内容を貼り付け、[実行] をクリックしてスクリプトを実行します。
比較ツールを使用してデータ モデルを同期する
普通の文章でのデータベースの変更の文書化は簡単ですが、変更を実装するには、開発者が運用データベースで一度に 1 つずつ変更を行う必要があります。変更 SQL コマンドを文書化すると、ボタンをクリックする簡単かつ迅速な操作でそれらの変更を運用データベースに実装できますが、データベース オブジェクトを作成および変更する SQL ステートメントと構文を学習して習得する必要があります。 データベース比較ツールは、両方のアプローチの良い面を活用し、悪い面を切り捨てます。
データベース比較ツールは、2 つのデータベースのスキーマまたはデータを比較し、データベースの違いを示す概要レポートを表示します。 次に、ボタンのクリックで、1 つ以上のデータベース オブジェクトを同期する SQL コマンドを生成できます。 要約すると、データベース比較ツールを使用して、デプロイ時に開発データベースと運用データベースを比較し、SQL コマンドを含むファイルを生成できます。このファイルは、実行時に運用データベースのスキーマに変更を適用して開発データベースのスキーマをミラーします。
多くの異なるベンダーが提供するさまざまなサード パーティのデータベース比較ツールがあります。 そのような例の 1 つに、"Red Gate Software" による "SQL Compare" があります。 SQL Compare を使用して、開発データベースと運用データベースのスキーマを比較および同期するプロセスを見てみましょう。
Note
この執筆時点では、SQL Compare の現在のバージョンはバージョン 7.1 で、Standard Edition のコストは 395 ドルでした。 無料の 14 日間試用版をダウンロードすると、この記事を読みながら操作を試すことができます。
SQL Compare を起動すると、[Comparison Projects] ダイアログ ボックスが開き、保存されている SQL Compare プロジェクトが表示されます。 新しいプロジェクトを作成します。 これにより、比較するデータベースに関する情報を求めるメッセージが表示される Project Configuration ウィザードが起動します (図 1 を参照)。 開発環境と運用環境のデータベースの情報を入力します。
図 1: 開発データベースと運用データベースを比較します (クリックするとフルサイズの画像が表示されます)
Note
開発環境データベースが Web サイトの App_Data
フォルダーにある SQL Express Edition データベース ファイルの場合、図 1 に示すダイアログ ボックスからデータベースを選択するには、データベースを SQL Server Express データベース サーバーに登録する必要があります。 これを行う最も簡単な方法は、SQL Server Management Studio (SSMS) を開き、SQL Server Express データベース サーバーに接続して、データベースをアタッチすることです。 SSMS がコンピューターにインストールされていない場合は、無料の "SQL Server Management Studio" をダウンロードしてインストールできます。
比較するデータベースを選択するだけでなく、[Options] タブからさまざまな比較設定を指定することもできます。有効にする候補になるオプションの 1 つは、[Ignore constraint and index names] です。前のチュートリアルで、アプリケーション サービスのデータベース オブジェクトを開発データベースと運用データベースに追加したことを思い出してください。 aspnet_regsql.exe
ツールを使用して運用データベース上にこれらのオブジェクトを作成した場合、主キー制約と一意制約の名前が開発データベースと運用データベースで異なっていることがわかります。 そのため、SQL Compare は、すべてのアプリケーション サービス テーブルに異なっていることを示すフラグを設定します。 [Ignore constraint and index names] をオフにしたままで制約の名前を同期することも、SQL Compare にこれらの違いを無視するように指示することもできます。
比較するデータベースを選択 (および比較オプションを確認) したら、[Compare Now] ボタンをクリックして比較を開始します。 次の数秒間で、SQL Compare は 2 つのデータベースのスキーマを調べ、それらの相違点のレポートを生成します。 このような不一致が SQL Compare インターフェイスでどのように表されるかを示すために、開発データベースにいくつかの変更を意図的に加えました。 図 2 に示すように、Authors
テーブルに BirthDate
列を追加し、Books
テーブルから ISBN
列を削除し、サイトを訪問するユーザーがレビューした書籍に評価を付けることができるようにするための新しいテーブル Ratings
を追加しました。
Note
このチュートリアルで行ったデータ モデルの変更は、データベース比較ツールの使用を説明するために行われました。 これらの変更は、今後のチュートリアルのデータベースには反映されません。
図 2: SQL Compare が開発データベースと運用データベースの違いを一覧表示します (クリックするとフルサイズの画像が表示されます)
SQL Compare は、データベース オブジェクトをグループに分割し、両方のデータベースに存在するが異なるオブジェクト、一方のデータベースに存在するが他方にはないオブジェクト、および同一のオブジェクトをすばやく示します。 ご覧のように、両方のデータベースに存在するが異なる 2 つのオブジェクトがあります。1 つの列が追加された Authors
テーブルと、削除された Books
テーブルです。 開発データベースにのみ存在するオブジェクトが 1 つあります。新しく作成された Ratings
テーブルです。 両方のデータベースで同一のオブジェクトが 117 個あります。
データベース オブジェクトを選択すると、[SQL Differences] ウィンドウが表示され、これらのオブジェクトの相違点を示します。 図 2 の下部に表示されている [SQL Differences] ウィンドウに、開発データベースの Authors
テーブルに BirthDate
列が存在することが強調表示されています。この列は、実稼働データベースの Authors
テーブルには見つかりません。
違いを確認し、同期するオブジェクトを選択したら、次の手順は、開発データベースと一致するように運用データベースのスキーマを更新するために必要な SQL コマンドを生成することです。 これは、Synchronization Wizard を使用して行います。 Synchronization Wizard は、同期するオブジェクトを確認し、アクション プランを要約します (図 3 を参照)。 データベースをすぐに同期することも、SQL コマンドを使用して自由に実行できるスクリプトを生成することもできます。
図 3: Synchronization Wizard を使用してデータベース スキーマを同期します (クリックするとフルサイズの画像が表示されます)
Red Gate Software の SQL Compare などのデータベース比較ツールを使用すると、開発データベース スキーマに対する変更を運用データベースにポイント アンド クリックで簡単に適用できます。
Note
SQL Compare は、2 つのデータベースの "スキーマ" を比較して同期します。 残念ながら、2 つのデータベース テーブル内のデータは比較および同期されません。 Red Gate Software は、2 つのデータベース間でデータを比較して同期する "SQL Data Compare" という名前の製品を提供していますが、これは SQL Compare とは別個の製品であり、さらに 395 ドルのコストがかかります。
デプロイ中にアプリケーションをオフラインにする
この一連のチュートリアルで説明したように、デプロイは複数の手順、つまり ASP.NET ページ、マスター ページ、CSS ファイル、JavaScript ファイル、イメージ、その他の必要なコンテンツの開発環境から運用環境へのコピー、運用環境に固有の構成情報のコピー (必要な場合)、前回のデプロイ以降のデータ モデルへの変更の適用を含むプロセスです。 ファイルの数とデータベースの変更の複雑さに応じて、これらの手順が完了するまでに数秒から数分かかる可能性があります。 この期間中、Web アプリケーションは流動的であり、サイトにアクセスするユーザーに対してエラーや予期しない動作が発生する可能性があります。
Web サイトをデプロイするときは、デプロイが完了するまで Web アプリケーションを "オフライン" にすることをお勧めします。 アプリケーションをオフラインにすること (およびデプロイ プロセスが完了したらオンラインに戻すこと) は、ファイルをアップロードしてから削除する簡単な作業です。 ASP.NET 2.0 以降は、アプリケーションのルート ディレクトリに app_offline.htm
という名前のファイルが存在するだけで、Web サイト全体が "オフライン" になります。そのサイトの ASP.NET ページへの要求は、app_offline.htm
ファイルの内容で自動的に応答されます。 そのファイルが削除されると、アプリケーションはオンラインに戻ります。
これで、デプロイ中にアプリケーションをオフラインにすることが、デプロイ プロセスを開始する前に、運用環境のルート ディレクトリに app_offline.htm
ファイルをアップロードし、デプロイが完了したら削除 (または別の名前に変更) する簡単な作業になります。 この手法の詳細については、John Peterson の ASP.NET アプリケーションをオフラインにする方法に関する記事を参照してください。
まとめ
データ ドリブン アプリケーションのデプロイの主な課題は、データベースのデプロイに集中しています。 データベースには 2 つのバージョン (開発環境に 1 つ、運用環境に 1 つ) があるため、開発で新機能が追加されると、これら 2 つのデータベース スキーマが同期しなくなる可能性があります。 さらに、運用データベースには実際のユーザーからの実際のデータが設定されているため、アプリケーションを構成するファイル (ASP.NET ページ、イメージ ファイルなど) をデプロイするときのように、変更された開発データベースで運用データベースを上書きすることはできません。 代わりに、データベースのデプロイ作業に、開発データベースに対して前回のデプロイ以降に行われた一連の変更を正確に運用データベースに実装する作業が伴います。
このチュートリアルでは、データベース変更のログを保守して適用するための 3 つの手法について説明しました。 最も簡単な方法は、普通の文章で変更を記録することです。 この方法では、運用データベースに対するこれらの変更の実装が手動になりますが、データベース オブジェクトを作成および変更するための SQL コマンドに関する知識は必要ありません。 より高度かつ、大規模プロジェクトや複数の開発者が参加するプロジェクトにより適合するアプローチは、一連の SQL コマンドとして変更を記録することです。 これにより、ターゲット データベースへのこれらの変更のロールアウトが大幅に迅速になります。 両方のアプローチの良い面を、Red Gate Software の SQL Compare などのデータベース比較ツールを使用して活用できます。
このチュートリアルで、データ ドリブン アプリケーションのデプロイに焦点をあてた説明を終わります。 次の一連のチュートリアルでは、運用環境のエラーに対応する方法について見ていきます。 黄色い死の画面ではなく、わかりやすいエラー ページを表示する方法について説明します。 エラーの詳細をログする方法と、そのようなエラーが発生したときにアラートを発行する方法についても説明します。
プログラミングに満足!