随着软件开发的复杂性增加,版本控制已经成为项目管理中不可或缺的一部分。团队目前使用的是SubVersion进行源代码管理,它在分支和合并方面的表现令人满意,极大地帮助了部署流程。然而,面临的挑战是,应用程序以数据库为中心,大量的业务逻辑存储在表、视图和存储过程中,这些并没有纳入源代码控制,更重要的是,没有变更历史记录。
为了解决这个问题,提出了两种解决方案。第一种是购买Microsoft Visual Studio 2008 Database Edition,它提供了一个强大的环境来处理数据库变更,类似于C#项目,并具有数据库逆向工程、架构和数据比较等许多功能。但这个解决方案的问题在于,它与Team Foundation Server(TFS)紧密绑定,而TFS并不是首选。此外,开发人员需要改变他们与数据库的交互方式。使用VSDE,他们需要创建脚本来修改数据库,然后对一个本地临时数据库执行这些脚本。虽然这在看来是最佳实践,但对于一些开发人员来说可能是个问题。
第二种解决方案是定期将数据库对象脚本化,并提交这些脚本到SubVersion。这种方法可以在不改变处理数据库方式的情况下,为提供数据库变更的历史记录。这个过程可以是自动化的,并且可以设置在服务器机器上,使用计划任务,每30分钟运行一次。如果想要更细粒度的历史记录,应该设置计划任务每15分钟或更短时间运行一次。需要注意的是,如果数据库没有变化,这个过程不会提交任何内容。
本教程将解释如何创建这个自动化过程。在开始研究这个问题时,寻找了一个命令行工具,它能够脚本化所有数据库对象。发现了很多不错的开源项目,它们以不同的方式做到了这一点:
和
。不幸的是,对于大型项目来说,每次都脚本化整个数据库是非常慢的,因此尝试创建一个自定义的控制台应用程序,使用
Microsoft.SqlServer.Management.Smo
只脚本当前运行和上一次运行之间的差异。
控制台应用程序分为两个类:
Program.cs
:应用程序的入口点,处理输入参数并调用辅助类来脚本化数据库对象。
ScripterHelper.cs
:辅助类使用
Microsoft.SqlServer.Management.Smo
来脚本化数据库对象。
辅助类将上次修改的对象日期存储在一个名为
的文本文件中,位于应用程序的路径下。这使得类在下一次运行时能够检测到已更改的对象,并只脚本化差异。在辅助类中,实现了一个逻辑来为数据库中的新/已删除对象添加/删除脚本文件。
通过一个简单的批处理文件,可以轻松地自动提交SubVersion中的更改。
最有趣的代码部分是如何使用
Microsoft.SqlServer.Management.Smo
来脚本化数据库对象。
执行此操作的类是
Scripter
:
Server server = new Server("(local)");
Database db = server.Databases["AdventureWorks"];
Scripter scripter = new Scripter();
scripter.Server = server;
scripter.Options.IncludeHeaders = true;
scripter.Options.SchemaQualify = true;
scripter.Options.SchemaQualifyForeignKeysReferences = true;
scripter.Options.NoCollation = true;
scripter.Options.DriAllConstraints = true;
scripter.Options.DriAll = true;
scripter.Options.DriAllKeys = true;
scripter.Options.DriIndexes = true;
scripter.Options.ClusteredIndexes = true;
scripter.Options.NonClusteredIndexes = true;
scripter.Options.ToFileOnly = true;
foreach(Table table in db.Tables)
{
if(!table.IsSystemObject)
{
scripter.Options.FileName = Path.Combine("C:\\Scripts", table.Name + ".sql");
scripter.Script(new Urn[] { table.Urn });
}
}
与SubVersion的集成是通过一个小型批处理文件完成的:
rem Script the database objects AdventureWorks under the local SQL Server into the folder C:\Scripts
SQLScripter.exe (local) AdventureWorks "C:\Scripts"
rem Change current Folder
C:\Scripts
rem Use for command to detect the file status and eventually add or delete the files from svn
for /f "tokens=2*" %%i in ('svn status ^| find "?"') do svn add %%i
for /f "tokens=2*" %%i in ('svn status ^| find "!"') do svn delete %%i
rem Commit the changes in svn
svn commit -m "Automatic commit" "C:\Scripts"
控制台应用程序接受以下参数: 服务器(要脚本化的数据库的主机) 数据库名称(要脚本化的数据库的名称) 脚本路径(应用程序将存储脚本的路径) 对象类型(过滤参数,用于限制将被脚本化的对象类型:t=表,v=视图,s=存储过程,a=用户定义的聚合,f=用户定义的函数,空=全部)