我们开发一个简单的脚本升级引擎,主要解决数据库脚本升级,通过应用程序统一升级不同版本应用程序的SQL,我们通过一张简单图来帮助理解:.

public interface IDBUpgradeStep{bool CanUpgrade(Version version);IDbConnection DbConnection { set; get; }Task Run();}
//该脚本表示在1.3.1 版本时,我们创建一张Order表public class DBUpgradeStepVersion1_3_1 : IDBUpgradeStep{static readonly Version targetVersion = new Version(1, 3, 1, 0);public IDbConnection DbConnection{get;set;}public bool CanUpgrade(Version version){return version < targetVersion;}public async Task Run(){//升级数据库var sql = @"CREATE TABLE ""Order""(orderId int,orderName varchar(255),costProce varchar(255));";await DbConnection.ExecuteAsync(sql);System.Diagnostics.Debug.Print(this.GetType().ToString() + " "+ sql);}}
//该脚本表示在1.6.0 版本时,我们为Order表新增TotalAmount字段public class DBUpgradeStepVersion1_6_0 : IDBUpgradeStep{static readonly Version targetVersion = new Version(1, 6, 0, 0);public IDbConnection DbConnection{get;set;}public bool CanUpgrade(Version version){return version < targetVersion;}public async Task Run(){//升级数据库var sql = @"Alter Table ""Order"" add TotalAmount money; ";await DbConnection.ExecuteAsync(sql);System.Diagnostics.Debug.Print(this.GetType().ToString() + " " + sql);}}
//该脚本表示在1.7.0 版本时,我们为Order表新增Description字段public class DBUpgradeStepVersion1_7_0 : IDBUpgradeStep{static readonly Version targetVersion = new Version(1, 7, 0, 0);public IDbConnection DbConnection{get;set;}public bool CanUpgrade(Version version){return version < targetVersion;}public async Task Run(){//升级数据库var sql = @"Alter Table ""Order"" add Description Varchar(255);";await DbConnection.ExecuteAsync(sql);System.Diagnostics.Debug.Print(this.GetType().ToString() + " " + sql);}}
//这是最后执行脚本,更新应用程序版本,使应用程序版本和数据库版本一致public class DBUpgradeStepFinal : IDBUpgradeStep{static readonly Version targetVersion = new ApplicationVersion().GetVersion();#region Memberspublic bool CanUpgrade(Version version){return version < targetVersion;}public IDbConnection DbConnection{get;set;}public async Task Run(){var sql = @"Update Version set Major=@Major,Minor=@Minor,Build=@Build,Revision=@Revision,LastModifiedDate=@LastModifiedDate";var param = new{Major = targetVersion.Major,Minor = targetVersion.Minor,Build = targetVersion.Build,Revision = targetVersion.Revision,LastModifiedDate = DateTime.Now};await DbConnection.ExecuteAsync(sql, param);}#endregion}
public interface IVersionInfo{Version CurVersion { get; }}
/// <summary>/// 获取应用程序版本/// </summary>public class ApplicationVersion :IVersionInfo{public Version CurVersion{get{return GetVersion();}}#region IVersionInfo Memberspublic Version GetVersion(){return GetType().Assembly.GetName().Version;}#endregion}
//获取当前数据库的版本public class DBVersion : IVersionInfo{private IDbConnection _dbConnection;private Version curVer = null;public DBVersion(IDbConnection dbConnection){_dbConnection =dbConnection;curVer = GetVersion();}public Version CurVersion { get { return curVer; } }#region IVersionInfo Memberspublic Version GetVersion(){try{Version ver = new Version(0, 0, 0, 0);var versionList = _dbConnection.Query<dynamic>("SELECT Major,Minor,Build,Revision FROM Version");var version = versionList.FirstOrDefault();if (version != null){int major = version.Major;int minor = version.Minor;int build = version.Build;int revision = version.Revision;ver = new Version(major, minor, build, revision);}return ver;}catch (Exception ex){throw;}}#endregion}
public class DatabaseUpgradeManager{private IDbConnection _dbConnection;private static readonly Version applicationVersion = new ApplicationVersion().GetVersion();private List<IDBUpgradeStep> steps = new List<IDBUpgradeStep>();/// <summary>/// Constructor./// </summary>/// <param name="sdfPath">The path of the SDF to be upgraded.</param>public DatabaseUpgradeManager(IDbConnection dbConnection){_dbConnection = dbConnection;DBVersionInfo = new DBVersion(dbConnection);}/// <summary>/// Add steps to this CEDatabaseUpgradeManager instance./// </summary>/// <param name="step">The step to be added.</param>public void AddSteps(IDBUpgradeStep step){step.DbConnection = _dbConnection;steps.Add(step);}/// <summary>/// Get the count of steps in this instance./// </summary>public int StepCount{get { return steps.Count; }}/// <summary>/// Get or set the DBVersion provider./// </summary>public IVersionInfo DBVersionInfo{set;get;}/// <summary>/// Execute the steps./// </summary>/// <returns>Return true if upgrade successfully, otherwise return false.</returns>public async Task<bool> DoUpgradeAsync(){Version dbVersion;try{foreach (IDBUpgradeStep step in this.steps){dbVersion = DBVersionInfo.CurVersion;if (dbVersion >= applicationVersion) break;if (step.CanUpgrade(dbVersion)){await step.Run();}}return true;}catch (Exception ex){return false;}}}
我们使用VS创建一个LocalDB数据库,命名为UpgrateDB,并创建一张Version表,并初始化表:
CREATE TABLE [dbo].[Version] ([Major] INT NOT NULL,[Minor] INT NOT NULL,[Build] INT NOT NULL,[Revision] INT NOT NULL,[LastModifiedDate] DATETIME NOT NULL);

假如我们现在要Release 2.0 版本,我们修改一下应用程序版本号:

public partial class MainWindow : Window{public MainWindow(){InitializeComponent();Loaded += MainWindow_Loaded;}private async void MainWindow_Loaded(object sender, RoutedEventArgs e){await UpgradeDatabaseAsync();}public async Task UpgradeDatabaseAsync(){var connection = new SqlConnection(@"Server=(localdb)\MSSQLLocalDB;Initial Catalog=UpgrateDB;Integrated Security=true");DatabaseUpgradeManager clientDBUpgrader = new DatabaseUpgradeManager(connection);#region upgrateclientDBUpgrader.AddSteps(new DBUpgradeStepVersion1_3_1());clientDBUpgrader.AddSteps(new DBUpgradeStepVersion1_6_0());clientDBUpgrader.AddSteps(new DBUpgradeStepVersion1_7_0());#endregionclientDBUpgrader.AddSteps(new DBUpgradeStepFinal());if (!await clientDBUpgrader.DoUpgradeAsync()){Application.Current.Shutdown(1);}}}
我们运行应用程序将执行的脚本打印出来,我们可以看到数据库从版本0升级到版本2.0 过程中的脚本都被执行了,我们还可以通过这种方式实现不同版本脚本升级到最新版本



备注:程序中涉及到ORM的部分使用了Dapper