自动脚本 SQL Server 2005 对象并在 Subversion 下提交





5.00/5 (10投票s)
自动脚本 SQL Server 2005 对象并在 Subversion 下提交。

引言
最近,我们把源代码控制从 Sourcesafe (我知道这已经过时了!) 更改为 SubVersion,除了遇到一些问题 (主要是培训方面的问题) 外,我们对它感到非常满意。我真的很喜欢分支和合并功能,这为我们的部署过程提供了很大的帮助。
不幸的是,这只对 C# 代码有所帮助,但是由于我们的应用程序是数据库中心的,并且很多业务逻辑都位于表、视图和存储过程中,实际上所有内容都没有在源代码控制之下,更重要的是,我们没有任何更改历史记录。
我建议解决这个问题的第一个方案是购买 Microsoft Visual Studio 2008 Database Edition,它实际上为我们提供了一个非常强大的环境来处理数据库更改,就像 C# 项目一样,并且具有很多功能,例如数据库逆向工程、模式和数据比较。 这个方案的第一个问题是 Microsoft Visual Studio 2008 Database Edition (VSDE) 与 Team Foundation Server (TFS) 紧密相连,而 TFS 并不是一个好的选择。
第二个问题是,开发人员需要改变他们使用数据库的方式。 事实上,他们将需要创建脚本来更改数据库,然后针对本地临时数据库运行它,而不是打开 SQL Management Studio 并直接更改数据库。 老实说,这在我看来是最好的工作方式,但这可能会对一些开发人员来说是一个问题。
我建议解决这个问题的第二个方案是定期编写数据库对象脚本并将这些脚本提交到 SubVersion 中。
这个解决方案将给我关于数据库更改的历史记录,而无需更改我们使用数据库的方式。这个过程可以是自动的,我可以在服务器机器上使用计划任务进行设置,每 30 分钟定期运行一次。如果您希望对您的历史记录有更高的粒度,您应该将计划程序设置为每 15 分钟或更短时间运行一次。请记住,如果数据库没有更改,该过程将不会提交任何内容。
本教程将解释如何创建此自动流程。
背景
当我开始调查这个问题时,我正在寻找一个命令行工具,该工具能够让我编写所有数据库对象的脚本。我找到了很多很好的开源项目,它们以不同的方式做到这一点
不幸的是,每次为大型项目编写整个数据库的脚本都非常慢,因此,我尝试创建一个自定义控制台应用程序,该应用程序使用 `Microsoft.SqlServer.Management.Smo` 仅脚本化当前运行和上一次运行之间的差异。
实现
控制台应用程序分为两个类
- Program.cs:处理输入参数并调用帮助程序类以编写数据库对象脚本的应用程序的入口点。
- ScripterHelper.cs:使用 `Microsoft.SqlServer.Management.Smo` 编写数据库对象脚本的帮助程序类。
帮助程序类将上次修改的对象的日期存储在名为 <Server>-<Database Name>.txt 的文本文件中,该文件位于应用程序的路径下。这使该类能够在下一次运行时检测已更改的对象并仅编写差异的脚本。我将一个逻辑嵌入到帮助程序类中,用于为数据库中新的/已删除的对象添加/删除脚本文件。
这样,使用一个简单的批处理文件,就可以轻松地自动在 SubVersion 中提交更改。
代码中最有趣的部分是如何使用 `Microsoft.SqlServer.Management.Smo` 编写数据库对象的脚本。
用于执行此操作的类是 `Scripter`
Server server = new Server("(local)"); // Server name of the database to script
Database db = server.Databases["AdventureWorks"] // Database name of the
// database to script
Scripter scripter = new Scripter(); // Class script the database objects
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) // Script all tables
{
if (!table.IsSystemObject) // Skip the system objects
{
scripter.Options.FileName =
Path.Combine("C:\Scripts", table.Name + ".sql"); // Filename of the script
scripter.Script(new Urn[] { table.Urn }); // Object to script
}
}
与 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"
Using the Code
控制台应用程序接受以下参数
- 服务器(要编写脚本的数据库的主机)
- 数据库名称(要编写脚本的数据库的名称)
- 脚本路径(应用程序将存储脚本的路径)
- 对象类型(用于限制要编写脚本的对象类型的筛选器参数:t = 表,v = 视图,s = 存储过程,a = 用户定义的聚合,f = 用户定义的函数,空=所有)
以下屏幕截图显示了创建的结果结构和 `AdventureWorks` 数据库的 *tables* 文件夹

关注点
这个解决方案可以改进以编写查找表的数据脚本并将其置于源代码控制之下。另一个想法是使用它来生成部署脚本并简化部署过程。
欢迎提出任何建议! :)
历史
- 2009 年 10 月 9 日 - 首次发布