好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Database Migration (下)

[Architecture Pattern] Database Migration (下)

接续...

[Architecture Pattern] Database Migration (上)

实作

范列下载

实作说明请参照范例程序内容: DatabaseMigrationSample点此下载

范列实作

首先建立封装数据库更新逻辑的DatabaseUpdater,以及定义DatabaseUpdater会使用到的各个接口。执行DatabaseUpdater的Update方法,系统会依照数据库更新逻辑,执行对应的DatabaseUpdatePlan。并且反复执行,直到数据库版本为目前DatabaseUpdatePlan能更新的最新版本。

?

public interface IDatabaseVersionManager

{

     // Methods

     string GetCurrentDatabaseVersion();

 

     void SetCurrentDatabaseVersion( string databaseVersion);

}

?

public interface IDatabaseUpdatePlanRepository

{

     // Methods

     IEnumerable<IDatabaseUpdatePlan> GetAllUpdatePlan();

}

?

public interface IDatabaseUpdatePlan

{

     // Properties

     string TargetDatabaseVersion { get ; }

 

     string ResultDatabaseVersion { get ; }

 

 

     // Methods

     void Execute();

}

?

public class DatabaseUpdater

{

     // Fields

     private readonly IDatabaseVersionManager _databaseVersionManager = null ;

 

     private readonly IDatabaseUpdatePlanRepository _databasePlanRepository = null ;

 

 

     // Constructor

     public DatabaseUpdater(IDatabaseVersionManager databaseVersionManager, IDatabaseUpdatePlanRepository databasePlanRepository)

     {

         #region Contracts

 

         if (databaseVersionManager == null ) throw new ArgumentNullException();

         if (databasePlanRepository == null ) throw new ArgumentNullException();

 

         #endregion

         _databaseVersionManager = databaseVersionManager;

         _databasePlanRepository = databasePlanRepository;

     }

 

 

     // Methods

     public void Update()

     {

         for (; ; )

         {

             if ( this .UpdateDatabase() == false )

             {

                 return ;

             }

         }

     }

 

     private bool UpdateDatabase()

     {

         // Get DatabaseVersion

         string databaseVersion = this .GetDatabaseVersion();

 

         // Get DatabaseUpdatePlan

         IDatabaseUpdatePlan databaseUpdatePlan = this .GetDatabaseUpdatePlan(databaseVersion);

         if (databaseUpdatePlan == null ) return false ;

 

         // Execute DatabaseUpdatePlan

         databaseUpdatePlan.Execute();

         databaseVersion = databaseUpdatePlan.ResultDatabaseVersion;

 

         // Set DatabaseVersion

         this .SetDatabaseVersion(databaseVersion);

 

         // Return

         return true ;

     }

 

     private string GetDatabaseVersion()

     {

         string databaseVersion = _databaseVersionManager.GetCurrentDatabaseVersion();

         if (databaseVersion == null ) databaseVersion = string .Empty;

         return databaseVersion;

     }

 

     private void SetDatabaseVersion( string databaseVersion)

     {

         #region Contracts

 

         if ( string .IsNullOrEmpty(databaseVersion) == true ) throw new ArgumentException();

 

         #endregion

 

         _databaseVersionManager.SetCurrentDatabaseVersion(databaseVersion);

     }

 

     private IDatabaseUpdatePlan GetDatabaseUpdatePlan( string databaseVersion)

     {

         #region Contracts

 

         if (databaseVersion == null ) throw new ArgumentNullException();

 

         #endregion

 

         foreach (IDatabaseUpdatePlan databaseUpdatePlan in _databasePlanRepository.GetAllUpdatePlan())

         {

             if (databaseUpdatePlan.TargetDatabaseVersion == databaseVersion)

             {

                 return databaseUpdatePlan;

             }

         }

         return null ;

     }

}

接着实作封装数据库版本管理职责的DatabaseVersionManager。实作范例中是将数据库版本的数据,存放到数据库中,由数据库描述自己目前的版本。并且DatabaseVersionManager在取得版本数据的时候,会特别检查数据库是否已经建立,这是用来处理建立第1.0版数据库的相关逻辑。

?

public class SqlDatabaseVersionManager : IDatabaseVersionManager

{

     // Fields

     private readonly string _connectionString = null ;

 

 

     // Constructor

     public SqlDatabaseVersionManager( string connectionString)

     {

         #region Contracts

 

         if ( string .IsNullOrEmpty(connectionString) == true ) throw new ArgumentException();

 

         #endregion

         _connectionString = connectionString;

     }

 

 

     // Methods

     public string GetCurrentDatabaseVersion()

     {

         // Check Database Exist

         if (( int )(SqlHelper.ExecuteScalar(_connectionString, @"SELECT COUNT(*) FROM sysdatabases WHERE name = N'MyDatabase'" )) == 0)

         {

             return string .Empty;

         }

 

         // Get DatabaseVersion

         string databaseVersion = ( string )(SqlHelper.ExecuteScalar(_connectionString, @"SELECT CurrentVersion FROM [MyDatabase].[dbo].[DatabaseVersion]" ));

         if (databaseVersion == null ) databaseVersion = string .Empty;

 

         // Return

         return databaseVersion;

     }

 

     public void SetCurrentDatabaseVersion( string databaseVersion)

     {

         #region Contracts

 

         if ( string .IsNullOrEmpty(databaseVersion) == true ) throw new ArgumentException();

 

         #endregion

 

         // Clear DatabaseVersion

         SqlHelper.ExecuteScalar(_connectionString, @"DELETE FROM [MyDatabase].[dbo].[DatabaseVersion]" );

 

         // Set DatabaseVersion

         SqlHelper.ExecuteScalar(_connectionString, @"INSERT INTO [MyDatabase].[dbo].[DatabaseVersion](CurrentVersion) VALUES('" + databaseVersion + "')" );

     }

}

接着建立第1.0版的DatabaseUpdatePlan。DatabaseUpdatePlan里,封装了目标版本、Schema变更、数据转换…等等职责。在第1.0版的DatabaseUpdatePlan最主要是为系统数据库加入了User这个数据表。并且第1.0版的DatabaseUpdatePlan跟其他版本的DatabaseUpdatePlan会有一个主要的差异在于:第1.0版的DatabaseUpdatePlan另外还要负责建立系统使用的数据库(MyDatabase)、记录数据库版本的数据表(DatabaseVersion)…等等必要设定。

?

public class SqlDatabaseUpdatePlanV1_0 : IDatabaseUpdatePlan

{

     // Fields

     private readonly string _connectionString = null ;

 

 

     // Constructor

     public SqlDatabaseUpdatePlanV1_0( string connectionString)

     {

         #region Contracts

 

         if ( string .IsNullOrEmpty(connectionString) == true ) throw new ArgumentException();

 

         #endregion

         _connectionString = connectionString;

     }

 

 

     // Properties

     public string TargetDatabaseVersion

     {

         get { return string .Empty; }

     }

 

     public string ResultDatabaseVersion

     {

         get { return @"MyDatabase V1.0" ; }

     }

 

 

     // Methods

     public void Execute()

     {

         // Create Database

         SqlHelper.ExecuteNonQuery(_connectionString, @"CREATE DATABASE MyDatabase" );

 

         // Add DatabaseVersion Table

         SqlHelper.ExecuteNonQuery(_connectionString, @"CREATE TABLE [MyDatabase].[dbo].[DatabaseVersion] (CurrentVersion nvarchar(50))" );

              

         // Add User Table

         SqlHelper.ExecuteNonQuery(_connectionString, @"CREATE TABLE [MyDatabase].[dbo].[User] (UserId nvarchar(50), UserName nvarchar(50))" );

     }       

}

接着建立第1.3版的DatabaseUpdatePlan。在第1.3版的DatabaseUpdatePlan最主要是为系统数据库加入了Company这个数据表。

?

public class SqlDatabaseUpdatePlanV1_3 : IDatabaseUpdatePlan

{

     // Fields

     private readonly string _connectionString = null ;

 

 

     // Constructor

     public SqlDatabaseUpdatePlanV1_3( string connectionString)

     {

         #region Contracts

 

         if ( string .IsNullOrEmpty(connectionString) == true ) throw new ArgumentException();

 

         #endregion

         _connectionString = connectionString;

     }

 

 

     // Properties

     public string TargetDatabaseVersion

     {

         get { return @"MyDatabase V1.0" ; }

     }

 

     public string ResultDatabaseVersion

     {

         get { return @"MyDatabase V1.3" ; }

     }

 

 

     // Methods

     public void Execute()

     {

         // Add Order Table

         SqlHelper.ExecuteNonQuery(_connectionString, @"CREATE TABLE [MyDatabase].[dbo].[Company] (CompanyId nvarchar(50), CompanyName nvarchar(50))" );

     }

}

再来建立封装更新计划管理职责的DatabaseUpdatePlanRepository。在范例程序中,为了简化所以采用Hard Code的方式,来管理DatabaseUpdatePlan。实际的项目中可以采用各种DI framework来完成DatabaseUpdatePlan生成注入的工作。

?

public class SqlDatabaseUpdatePlanRepository : IDatabaseUpdatePlanRepository

{

     // Fields

     private readonly string _connectionString = null ;

 

 

     // Constructor

     public SqlDatabaseUpdatePlanRepository( string connectionString)

     {

         #region Contracts

 

         if ( string .IsNullOrEmpty(connectionString) == true ) throw new ArgumentException();

 

         #endregion

         _connectionString = connectionString;

     }

 

 

     // Methods

     public IEnumerable<IDatabaseUpdatePlan> GetAllUpdatePlan()

     {

         IDatabaseUpdatePlan[] databaseUpdatePlanArray = new IDatabaseUpdatePlan[]

         {

             new SqlDatabaseUpdatePlanV1_0(_connectionString),

             new SqlDatabaseUpdatePlanV1_3(_connectionString),

         };

         return databaseUpdatePlanArray;

     }       

}

最后执行生成建立DatabaseUpdater的ConsoleApplication程序。就可以看到原本空白的数据库,建立了系统必要的数据库、数据表。而检查程序建立的数据表内容,可以发现第1.3版本才加入的Company数据表,这也就是说数据库已经升级成为了第1.3版的数据库。(记得重新整理,才能看到更新资料)

?

class Program

{

     static void Main( string [] args)

     {

         // Setting

         string connectionString = @"Data Source=CLARK-HOME\SQLEXPRESS;Integrated Security=True" ;

 

         // Create

         DatabaseUpdater databaseUpdater = CreateDatabaseUpdater(connectionString);

 

         // Update

         databaseUpdater.Update();

 

         // End

         Console.WriteLine( "End..." );

         Console.ReadLine();

     }

 

     static DatabaseUpdater CreateDatabaseUpdater( string connectionString)

     {

         #region Contracts

 

         if ( string .IsNullOrEmpty(connectionString) == true ) throw new ArgumentException();

 

         #endregion

 

         // DatabaseVersionManager

         IDatabaseVersionManager databaseVersionManager = new SqlDatabaseVersionManager(connectionString);

 

         // DatabasePlanRepository

         IDatabaseUpdatePlanRepository databasePlanRepository = new SqlDatabaseUpdatePlanRepository(connectionString);

 

         // DatabaseUpdater

         DatabaseUpdater databaseUpdater = new DatabaseUpdater(databaseVersionManager, databasePlanRepository);

 

         // Return

         return databaseUpdater;

     }

}

到目前为止,范例程序验证了从无到有的生成数据库。接下来的范例程序,用来示范升级数据库版本的功能。首先建立第2.0版的DatabaseUpdatePlan。在第2.0版的DatabaseUpdatePlan最主要是为系统数据库加入了Order这个数据表。

?

public class SqlDatabaseUpdatePlanV2_0 : IDatabaseUpdatePlan

{

     // Fields

     private readonly string _connectionString = null ;

 

 

     // Constructor

     public SqlDatabaseUpdatePlanV2_0( string connectionString)

     {

         #region Contracts

 

         if ( string .IsNullOrEmpty(connectionString) == true ) throw new ArgumentException();

 

         #endregion

         _connectionString = connectionString;

     }

 

 

     // Properties

     public string TargetDatabaseVersion

     {

         get { return @"MyDatabase V1.3" ; }

     }

 

     public string ResultDatabaseVersion

     {

         get { return @"MyDatabase V2.0" ; }

     }

 

 

     // Methods

     public void Execute()

     {

         // Add Order Table

         SqlHelper.ExecuteNonQuery(_connectionString, @"CREATE TABLE [MyDatabase].[dbo].[Order] (OrderId nvarchar(50), OrderName nvarchar(50))" );

     }

}

接着将建立完成的第2.0版DatabaseUpdatePlan加入DatabaseUpdatePlanRepository。

?

public class SqlDatabaseUpdatePlanRepository : IDatabaseUpdatePlanRepository

{

     // Fields

     private readonly string _connectionString = null ;

 

 

     // Constructor

     public SqlDatabaseUpdatePlanRepository( string connectionString)

     {

         #region Contracts

 

         if ( string .IsNullOrEmpty(connectionString) == true ) throw new ArgumentException();

 

         #endregion

         _connectionString = connectionString;

     }

 

 

     // Methods

     public IEnumerable<IDatabaseUpdatePlan> GetAllUpdatePlan()

     {

         IDatabaseUpdatePlan[] databaseUpdatePlanArray = new IDatabaseUpdatePlan[]

         {

             new SqlDatabaseUpdatePlanV1_0(_connectionString),

             new SqlDatabaseUpdatePlanV1_3(_connectionString),

             new SqlDatabaseUpdatePlanV2_0(_connectionString),

         };

         return databaseUpdatePlanArray;

     }  

}

最后执行先前建立的ConsoleApplication程序。就可以看到原本第1.3版的数据库内,加入第2.0版的Order数据表,这也就是说数据库已经升级成为了第2.0版的数据库。(记得重新整理,才能看到更新资料)

后记

碍于篇幅的关系,DatabaseUpdater简化了很多的功能设计,例如:在DatabaseUpdater加入数据库的备份与还原功能,以提高系统的可用性。或者是在DatabaseUpdater里加入升级到特定版本的功能,以增加工具的重用性。还有其他一些重要的功能,这些功能都有很大的用处。开发人员在实际项目的建置时,可以视项目需求来加入实作。

另外不管是微软产品还是其他软件产品,都有与Database Migration功能相近的软件实作。

相关数据可以参考:
- Entity Framework - 使用Code First的Enabling Migrations(Code-Base)
- 在Django里做Database Migration

期許自己~
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。

分类:  Architecture Pattern

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于Database Migration (下)的详细内容...

  阅读:37次