65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (50投票s)

2011年2月27日

CPOL

6分钟阅读

viewsIcon

112780

downloadIcon

3898

在本文中,我将向您展示如何使用 SMO 的脚本功能。

SMOScripting.jpg

引言

本文是关于编程服务器管理对象 (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 有一个接受三个参数(serverInstanceuserNamepassword)的构造函数。所有参数都从 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 对象建立服务器连接。接下来,创建 ScripterScriptingOptions 对象。然后创建一个 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 日 - 文章创建。
© . All rights reserved.