ご挨拶!
この投稿では、データベースと特にMSSQLの変更のサポートと移行のトピックに関する私の考えと、私の決定を共有したいと思います。
問題
原則として、多かれ少なかれ深刻なプロジェクトでは、いくつかの独立した環境(環境)があります。
開発者は自分のデータベースを使用してシステムコードを記述およびデバッグし、コードの変更とデータベーススキーマをテスターの環境に転送してから、ステージングとプロダクションに転送します。
繰り返しになりますが、多かれ少なかれ深刻なプロジェクトでは、開発者とテスターには環境もあります。
したがって、コード内だけでなくデータベース内の変更の移行プロセスも整理する必要があり、このプロセスが便利で信頼できることが望ましい。
カットの下の詳細。
問題を解決するためのオプション
プロジェクトに参加した私の経験に基づいて、データベースの変更を移行するプロセスを整理するいくつかの方法を特定できます。
1.製品の各バージョンのコードリポジトリには、番号の下にスクリプトが追加される個別のフォルダーが作成されます。 各バージョンごとに。 この場合、すべてのデータベースを監視し、コードの現在のバージョンとの関連性とコンプライアンスを維持する個別の展開エンジニアが必要です。 このプロセスは、定期的および計画的リリースのプロジェクトに正常に適用できますが、継続的リリースの場合、すでに問題になる可能性があります。
2.開発者がパッチを送信するデータベーススキームを担当する専任の担当者がいます。 これらのパッチはソースコードリポジトリに追加され、2つの異なるbatスクリプトによってデプロイされます。1つは環境を再度作成し、2つ目はパッチを適用するだけです。 このアプローチを使用すると、データベースのコードバージョンを一致させる問題は大幅に軽減されますが、どの変更が誰によって、いつ行われたかを追跡することははるかに困難です。 エラーの可能性が高い。
3.最後に、最後のオプションであり、私に最も近いオプションは、 FluentMigrator 、.Net Migratorなどのデータベースバージョンを移行するための特別なフレームワークの使用です。
私の決断
プロジェクトの1つについて、データベースバージョンの移行の問題を大幅に簡素化するアプリケーションを作成しました。
コードは非常にリベラルなMITライセンスの下でCodePlex.comに投稿されているため、この製品を都合の良いときに使用できます。
システムは、2つのプロジェクトで構成されるWinFormアプリケーションです。 移行のフレームワークとしてFluentMigratorが使用されます。 FluentMigratorとは何か、これと一緒に食べるものについては詳しく説明しません;このフレームワークの詳細を読みたい人は、この記事FluentMigrator-バージョン管理された移行システムを参照してください。
私のプロジェクトは、「C#Database Migrator」という簡単な名前で、 https : //csharpdatabasemigrator.codeplex.com/にあります。
システムでできること:
1.複数のタイプのデータベースを操作します。つまり、異なる構造を持つデータベースの移行を作成できます。 これがコードでどのように行われるかは少し低くなります。
2.システムは、データベースのバックアップを作成し、それらを復元できます。
3.移行として、すべての.sqlファイルが含まれるディレクトリを使用できます。
4.移行ファイルで、データベースの名前を確認できます。 これは、一部のデータがテストベースのみを取得する場合、またはその逆の場合に役立ちます。
使用を開始する方法
1.プロジェクトソースhttps://csharpdatabasemigrator.codeplex.com/SourceControl/latestを選択します
2.スタジオでプロジェクトを開く
3.デフォルトフォルダー(移行ファイルのデフォルトフォルダー)に移動します。
4.移行ファイルを作成します。 移行ファイルは、基本クラスMigrationから継承されたクラスです
using FluentMigrator; namespace Migrations.Default { [Migration(1, "Author: AuthorName; Description")] public class Migration_1: Migration { public override void Up() { // Migration Up code here } public override void Down() { // Migration Down code here } } }
5.クラス属性に、バージョン番号とその説明、および移行用のコード自体を記述します。 たとえば、新しいテーブルを作成する
Create.Table("Users") .WithIdColumn() .WithColumn("Name").AsString().NotNullable();
SQLコマンドを実行できます。
Execute.Sql("DELETE TABLE Users");
ここで構文の詳細を読むことができます: https : //github.com/schambers/fluentmigrator/wiki/Fluent-Interface
6.プロジェクトをコンパイルし、アプリケーションを実行します。
7.データベースサーバーに接続する
8.ドロップダウンリストで必要なデータベースを選択します
9.操作のタイプ「最新バージョンに更新」を選択し、「ジョブを実行」ボタンを押します
10.フォームの右側のログを確認します
いくつかのタイプのデータベースを使用する方法
同じデータベーススキーマに属するすべての移行ファイルは、同じネームスペースに存在する必要があります。 デフォルトでは、これはプロジェクト内のフォルダーの名前による「Migrations.Default」です。 別の種類の移行を追加するには、移行プロジェクトに別のフォルダー(MySecondDatabaseなど)を作成し、構成ファイルMigrationNamespaces.configを編集する必要があります。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <MigrationNamespaces> <MigrationNamespace Name="Default" Path="Migrations.Default"/> <MigrationNamespace Name="My Second Database" Path="Migrations.MySecondDatabase"/> </MigrationNamespaces> </configuration>
その後、メインアプリケーションウィンドウで「My Second Database」タイプが使用可能になります。
フォルダーからのSQLファイルの実行
1.システムは、指定されたフォルダーのファイルを移行として使用できます。 すべてのファイルは名前でソートされ、移行が適用されると実行されます。
すべての仕組み
c#コードから移行を実行するには、FluentMigrator.Runnerアセンブリを接続し、1つのメソッドを実行する必要があります。
public Action<string> OnNewUpdateLog; public void UpdateToLatestVersion(string databaseName, string migrationNamespace) { // , FluentMigrator-a var announcer = new TextWriterAnnouncer(OnNewUpdateLog); // var assembly = Assembly.GetExecutingAssembly(); // , var migrationContext = new RunnerContext(announcer) { Namespace = migrationNamespace }; var options = new MigrationOptions { PreviewOnly = false, Timeout = 60 }; // SqlServer2008 var factory = new FluentMigrator.Runner.Processors.SqlServer.SqlServer2008ProcessorFactory(); var processor = factory.Create(GetConnectionString(databaseName), announcer, options); // runner var runner = new MigrationRunner(assembly, migrationContext, processor); // runner.MigrateUp(true); OnNewUpdateLog("Done"); }
データベースのバックアップを作成および復元するには、2つの方法があります。
public void BackupDatabase(string databaseName, string destinationPath) { var sqlServer = new Server(_connection); databaseName = databaseName.Replace("[", "").Replace("]", ""); var sqlBackup = new Backup { Action = BackupActionType.Database, BackupSetDescription = "ArchiveDataBase:" + DateTime.Now.ToShortDateString(), BackupSetName = "Archive", Database = databaseName }; var deviceItem = new BackupDeviceItem(destinationPath, DeviceType.File); sqlBackup.Initialize = true; sqlBackup.Checksum = true; sqlBackup.ContinueAfterError = true; sqlBackup.Devices.Add(deviceItem); sqlBackup.Incremental = false; sqlBackup.ExpirationDate = DateTime.Now.AddDays(3); sqlBackup.LogTruncation = BackupTruncateLogType.Truncate; sqlBackup.PercentCompleteNotification = 10; sqlBackup.PercentComplete += (sender, e) => OnSqlBackupPercentComplete(e.Percent, e.Message); sqlBackup.Complete += (sender, e) => OnSqlBackupComplete(e.Error); sqlBackup.FormatMedia = false; sqlBackup.SqlBackup(sqlServer); } public void RestoreDatabase(string databaseName, string filePath) { var sqlServer = new Server(_connection); databaseName = databaseName.Replace("[", "").Replace("]", ""); var sqlRestore = new Restore(); sqlRestore.PercentCompleteNotification = 10; sqlRestore.PercentComplete += (sender, e) => OnSqlRestorePercentComplete(e.Percent, e.Message); sqlRestore.Complete += (sender, e) => OnSqlRestoreComplete(e.Error); var deviceItem = new BackupDeviceItem(filePath, DeviceType.File); sqlRestore.Devices.Add(deviceItem); sqlRestore.Database = databaseName; DataTable dtFileList = sqlRestore.ReadFileList(sqlServer); int lastIndexOf = dtFileList.Rows[1][1].ToString().LastIndexOf(@"\"); string physicalName = dtFileList.Rows[1][1].ToString().Substring(0, lastIndexOf + 1); string dbLogicalName = dtFileList.Rows[0][0].ToString(); if (!Directory.Exists(physicalName)) { physicalName = sqlServer.MasterDBPath + "\\"; } string dbPhysicalName = physicalName + databaseName + ".mdf"; string logLogicalName = dtFileList.Rows[1][0].ToString(); string logPhysicalName = physicalName + databaseName + "_log.ldf"; sqlRestore.RelocateFiles.Add(new RelocateFile(dbLogicalName, dbPhysicalName)); sqlRestore.RelocateFiles.Add(new RelocateFile(logLogicalName, logPhysicalName)); sqlServer.KillAllProcesses(sqlRestore.Database); Database db = sqlServer.Databases[databaseName]; if (db != null) { db.DatabaseOptions.UserAccess = DatabaseUserAccess.Single; db.Alter(TerminationClause.RollbackTransactionsImmediately); sqlServer.DetachDatabase(sqlRestore.Database, false); } sqlRestore.Action = RestoreActionType.Database; sqlRestore.ReplaceDatabase = true; sqlRestore.SqlRestore(sqlServer); db = sqlServer.Databases[databaseName]; db.SetOnline(); sqlServer.Refresh(); db.DatabaseOptions.UserAccess = DatabaseUserAccess.Multiple; }
DatabaseManager.csクラスの詳細
みんなありがとう!