SMO 教程 n 的第 3 部分 - 脚本






4.93/5 (50投票s)
在本文中,我将向您展示如何使用 SMO 的脚本功能。
引言
本文是关于编程服务器管理对象 (Server Management Objects) 系列文章的第三部分。在 第一篇文章中,我介绍了什么是服务器管理对象。我们还学习了如何处理数据库存储对象。在 第二篇文章中,我介绍了如何使用与数据库存储对象无关的类。在本文中,我将演示如何使用 SMO 的脚本功能。
背景
SQL Server 客户端工具在创建数据库对象脚本方面具有非常强大的功能,但它们并不总能提供程序员所需的足够功能来生成脚本。这些自定义脚本可用于数据库文档。因此,数据库管理员和开发人员必须编写自定义脚本生成器。这些生成器通常将脚本生成到文本文件中,然后可以存储在源代码管理系统中并进行版本控制。可以使用 SMO 对象创建自定义生成器。SMO 中的脚本由 Scripter
对象及其子对象控制。通过指定的列表和脚本选项生成脚本。结果作为 StringCollection
系统对象返回。
要开始使用 SMO,首先必须在 Visual Studio 中添加引用。在“添加引用”窗口中,选择
Microsoft.SqlServer.Smo
Microsoft.SqlServer.SmoExtended
Microsoft.SqlServer.Management.Sdk.Sfc
Mircorost.SqlServer.ConnectionInfo
添加这些引用后,您必须为这两个命名空间添加两个 using
语句
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
用于脚本操作的 SMO 类
Scripter |
提供对脚本设置和功能的编程访问,包括查找依赖项、输出脚本以及管理脚本操作的上下文。 |
ScriptingErrorEventArgs |
表示在脚本操作期间报告错误的参数。ScriptingErrorEventArgs 派生自 EventArgs 。 |
ScriptingOptions |
表示脚本操作的选项。这些选项标识要脚本化的 SQL Server 项并控制脚本操作。 |
ScriptOption |
表示 SQL Server 脚本选项。ScriptOption 类包含一个属性,用于表示可以脚本化的每种类型的 SQL Server 项。 |
使用代码
这个简单的项目包含一个名为 Form1
的窗体。要连接到 SQL Server 2005(或更高版本),使用 Server
类非常重要。该类的一个重载构造函数接受一个 ServerConnection
对象。该对象表示与服务器的连接。ServerConnection
有一个接受三个参数(serverInstance
、userName
和 password
)的构造函数。所有参数都从 app.config 文件加载。
string serverstr = ConfigurationManager.AppSettings["Server"];
string user = ConfigurationManager.AppSettings["User"];
string password = ConfigurationManager.AppSettings["Password"];
ServerConnection conn = new ServerConnection(serverstr, user, password);
try
{
Server server = new Server(conn);
foreach (Database database in server.Databases)
{
cboDatabase.Items.Add(database.Name);
}
cboDatabase.SelectedIndex = 0;
}
catch (Exception err)
{
MessageBox.Show(err.Message, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
使用此代码,您可以使用 app.config 文件中指定的凭据连接到 SQL Server 实例。连接成功后,dboDatabase
将填充数据库列表。
在生成脚本之前,选择要脚本化的对象类型非常重要。此选择在“对象”面板中提供。您可以从四种对象类型(存储过程、用户定义函数、视图和表)中进行选择。脚本选项可以在“脚本选项”面板中选择。
脚本标题 | 获取或设置一个布尔属性值,该值指定生成的脚本是否以包含生成日期和时间的标题为前缀。如果为 True ,则包含标题信息。否则为 False (默认)。 |
脚本权限 | 获取或设置一个布尔属性值,该值指定是否将所有权限包含在生成的脚本中。如果为 True ,则所有权限都包含在脚本中。否则为 False (默认)。 |
脚本扩展属性 | 获取或设置一个布尔属性值,该值指定是否将扩展对象属性包含在生成的脚本中。如果为 True ,则将扩展对象属性包含在生成的脚本中。否则为 False (默认)。 |
脚本 IF NOT EXISTS | 获取或设置一个布尔属性值,该值指定在将对象包含在脚本中之前是否检查其是否存在。如果为 True ,则在将对象包含在脚本中之前验证其是否存在。否则为 False (默认)。 |
脚本 DROP | 获取或设置一个布尔属性值,该值指定脚本操作是否生成用于删除引用的组件的 Transact-SQL 脚本。如果为 True ,则脚本操作生成用于删除引用的组件的 Transact-SQL 脚本。如果为 False (默认),则脚本操作生成用于创建引用的组件的 Transact-SQL 脚本。 |
脚本 DB 上下文 | 获取或设置一个布尔属性值,该值指定是否将数据库上下文包含在生成的脚本中。如果为 True ,则将数据库上下文包含在生成的脚本中。否则为 False (默认)。 |
脚本数据库 | 如果选择了此选项,则创建数据库的 Create 语句。 |
脚本无排序规则 | 获取或设置一个布尔属性值,该值指定是否将排序规则子句包含在生成的脚本中。如果为 True ,则不包含排序规则子句。否则为 False (默认)。 |
脚本无文件组 | 获取或设置一个布尔属性值,该值指定是否将 'ON <filegroup> ' 子句包含在生成的脚本中。如果为 True ,则不将文件组子句包含在脚本中。否则为 False (默认)。 |
脚本无标识 | 获取或设置一个布尔属性值,该值指定是否将标识属性种子和增量的定义包含在生成的脚本中。如果为 True ,则不将标识属性种子和增量的定义包含在生成的脚本中。否则为 False (默认)。 |
ScriptingOprions
的所有属性都可以在 此处找到。
脚本生成在单击“Script”按钮后开始。初始化 BackgroundWorker
对象并调用 RunWorkerAsync()
方法。BackgroundWorker
类在单独的线程上执行操作。我决定使用这种方法,因为脚本化多个对象可能会导致用户界面在操作运行时停止响应。我在 DoWork
事件处理程序中添加了脚本代码。
private void btnScript_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
this.Invoke(new MethodInvoker(delegate
{
richTextScript.Text = "";
txtProgress.Text = "";
}));
string serverstr = ConfigurationManager.AppSettings["Server"];
string user = ConfigurationManager.AppSettings["User"];
string password = ConfigurationManager.AppSettings["Password"];
ServerConnection conn = new ServerConnection(serverstr, user, password);
try
{
Server server = new Server(conn);
string dbname = "";
this.Invoke(new MethodInvoker(delegate
{
dbname = cboDatabase.SelectedItem.ToString();
}));
Database db = server.Databases[dbname];
Scripter scripter = new Scripter(server);
scripter.ScriptingProgress +=
new ProgressReportEventHandler(ScriptingProgressEventHandler);
ScriptingOptions so = new ScriptingOptions();
so.IncludeIfNotExists = chkScriptIfNotExists.Checked;
so.IncludeHeaders = chkScriptHeaders.Checked;
so.Permissions = chkScriptPermissions.Checked;
so.ExtendedProperties = chkScriptExtendedProperties.Checked;
so.ScriptDrops = chkScriptDrop.Checked;
so.IncludeDatabaseContext = chkDBContext.Checked;
so.NoCollation = chkNoCollation.Checked;
so.NoFileGroup = chkNoFileGroups.Checked;
so.NoIdentities = chkNoIdentities.Checked;
StringBuilder sbScript = new StringBuilder();
int version = 0;
this.Invoke(new MethodInvoker(delegate
{
version = cboServerVersion.SelectedIndex;
}));
switch (version)
{
case 0:
so.TargetServerVersion = SqlServerVersion.Version80;
break;
case 1:
so.TargetServerVersion = SqlServerVersion.Version90;
break;
case 2:
so.TargetServerVersion = SqlServerVersion.Version100;
break;
}
scripter.Options = so;
if (chkScriptDatabase.Checked)
{
sbScript.Append(ScriptObject(new Urn[] { db.Urn }, scripter));
}
if (chkTables.Checked)
{
server.SetDefaultInitFields(typeof(Table), "IsSystemObject");
foreach (Table tb in db.Tables)
{
if (!tb.IsSystemObject)
{
sbScript.Append(ScriptObject(new Urn[] { tb.Urn }, scripter));
}
}
}
if (chkViews.Checked)
{
server.SetDefaultInitFields(typeof(Microsoft.SqlServer.Management.Smo.View),
"IsSystemObject");
foreach (Microsoft.SqlServer.Management.Smo.View v in db.Views)
{
if (!v.IsSystemObject)
{
sbScript.Append(ScriptObject(new Urn[] { v.Urn }, scripter));
}
}
}
if (chkUserDefinedFunctions.Checked)
{
server.SetDefaultInitFields(typeof(UserDefinedFunction), "IsSystemObject");
foreach (UserDefinedFunction udf in db.UserDefinedFunctions)
{
if (!udf.IsSystemObject)
{
sbScript.Append(ScriptObject(new Urn[] { udf.Urn }, scripter));
}
}
}
if (chkStoredProcedures.Checked)
{
server.SetDefaultInitFields(typeof(StoredProcedure), "IsSystemObject");
foreach (StoredProcedure sp in db.StoredProcedures)
{
if (!sp.IsSystemObject)
{
sbScript.Append(ScriptObject(new Urn[] { sp.Urn }, scripter));
}
}
}
this.Invoke(new MethodInvoker(delegate
{
richTextScript.Text = sbScript.ToString();
}));
Parse();
conn.Disconnect();
}
catch (Exception err)
{
MessageBox.Show(err.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
上面的代码演示了脚本生成。在脚本化之前,使用 app.config 文件中指定的凭据通过 Server
对象建立服务器连接。接下来,创建 Scripter
和 ScriptingOptions
对象。然后创建一个 StringBuilder
对象 sbScript
。脚本存储在此对象中,当所有脚本创建完成后,sbScript
的文本将显示在 richTextScript
对象中。
private string ScriptObject(Urn[] urns, Scripter scripter)
{
StringCollection sc = scripter.Script(urns);
StringBuilder sb = new StringBuilder();
foreach (string str in sc)
{
sb.Append(str + Environment.NewLine + "GO" +
Environment.NewLine + Environment.NewLine);
}
return sb.ToString();
}
Scripter
类的 Script( )
方法生成 T-SQL,可用于创建由传递给构造函数的 SqlSmoObject
数组、Urn
数组或 UrnCollection
对象标识的 SQL Server 对象。Script( )
方法将 T-SQL 作为 StringCollection
对象返回。Options
属性公开一个 ScriptingOptions
对象,允许您控制脚本操作。
所有脚本成功生成后,它们将通过 Parse()
方法进行解析和高亮显示。要高亮显示的关键字存储在 SQL.txt 文件中。有关语法高亮的更多信息,请访问
历史
- 2011 年 2 月 27 日 - 文章创建。