Getting Started With SQL Server Management Objects (SMO) : Usage Scenario
Getting Started With SQL Server Management Objects (SMO) : Usage Scenario
Problem
In my last article, Getting started with SQL Server Management Objects (SMO), I discussed what SMO is, how you can
start working with SMO, how to connect to SQL server, how to enumerate through the different SQL objects, create a
database, create a table etc, all programmatically.
In this tip I would like to take you on an SMO ride to generate SQL object scripts programmatically. Though you can do this
through SQL Server Management Studio (SSMS) there might be times (more details on usage scenarios given below) when
you would need to create SQL scripts automatically.
Solution
As I discussed in my last tip, SQL Server objects are represented as object hierarchies inside SMO, for example a Server
object is a collection of Database objects. A Database object is a collection of a Table (though there are couple of other
collection inside the Database object as well such as Stored Procedure, Views, User-defined Functions etc). A Table is a
collection of a Column and so on.
Every object in this hierarchy has a method called a script, which returns a string collection of scripts. Apart from that,
SMO provides a utility class, Scripter, which generates the script in a more efficient way. For example, the Scripter class
can discover the relationships between objects and can provide scripts for dependencies as well and it can respond to
Progress and Error events.
Usage Scenario
As I said, SQL Server Management Studio (SSMS) provides a wizard type interface to script out all or selected objects, but
there might be some scenarios, some of them are discussed below, where you would consider the use of SMO instead of
SSMS.
• You want to create a tool which will automatically set up (or sync) an environment for dev or test which resembles
the production environment.
• You have a data warehouse database, in this database data is not that important (or even the data size is so big,
taking a backup of the entire database would not be feasible) as data can again be pulled from the source systems
but you want to make sure the schema objects are scripted and backed up automatically so that you can re-create
the database in case of a disaster.
• Programmatically you want to control the backup and restore process of database administration (I will cover this
in more detail in another tip "Backup and Restore Programmatically with SMO").
• Programmatically you want to transfer a database schema and data to another instance of SQL Server. (I will cover
this in more detail in another tip "Transferring schema objects and data programmatically with SMO").
Example
Before you start writing your code using SMO, you need to take reference of several assemblies which contain different
namespaces to work with SMO. For more details on what these assemblies are and how to reference them in your code,
refer to my tip Getting started with SQL Server Management Objects (SMO).
C# Code Block 1 - Here I am using the Scripter utility class to generate the script for two selected databases. Two
Database objects are created first; one of them refers to the AdventureWorks database and another one refers to
AdventureWorksDW. The script method of the scripter object is called which takes database object URN (Unique
Resource Name) as input and returns a string collection of scripts. URN is a new concept in SMO (this was not available in
SQL-DMO) which provides similar notation like XPath to denote object hierarchy.
C# Code Block 3
Generating table script with all dependencies and DRI objects
C# Code Block 4
Generating scripts for table collection along with all the indexes on the table
C# Code Block 5
Generating Script for objects in memory even before creating on the server
Output:
The complete code listing (created on SQL Server 2008 and Visual Studio 2008, though there is not much difference if you
are using it on SQL Server 2005 and Visual Studio 2005) can be found in the below text box.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using
System.Collections.Specialized; using Microsoft.SqlServer.Management.Smo; using
Microsoft.SqlServer.Management.Common; using Microsoft.SqlServer.Management.Sdk.Sfc; namespace
SQLScriptGenerationProgrammatically { class Program { static void Main(string[] args) { Server myServer = new
Server(@"ARSHADALI-LAP\ARSHADALI"); try { //Using windows authentication
myServer.ConnectionContext.LoginSecure = true; myServer.ConnectionContext.Connect(); //GenerateDBScript(myServer);
//GenerateTableScript(myServer); //GenerateTableScriptWithDependencies(myServer);
//GenerateTableScriptWithIndexes(myServer); GenerateScriptWithoutCreatingObjectOnServer(myServer); } catch
(Exception ex) { Console.WriteLine(ex.Message); } finally { if (myServer.ConnectionContext.IsOpen)
myServer.ConnectionContext.Disconnect(); Console.WriteLine("Press any key to terminate...."); Console.ReadKey(); } }
private static void GenerateDBScript(Server myServer) { Scripter scripter = new Scripter(myServer); Database
myAdventureWorks = myServer.Databases["AdventureWorks"]; StringCollection scriptCollection = scripter.Script(new
Urn[] { myAdventureWorks.Urn }); foreach (string script in scriptCollection) Console.WriteLine(script); } private static
void GenerateTableScript(Server myServer) { Scripter scripter = new Scripter(myServer); Database myAdventureWorks =
myServer.Databases["AdventureWorks"]; /* With ScriptingOptions you can specify different scripting * options, for
example to include IF NOT EXISTS, DROP * statements, output location etc*/ ScriptingOptions scriptOptions = new
ScriptingOptions(); scriptOptions.ScriptDrops = true; scriptOptions.IncludeIfNotExists = true; foreach (Table myTable in
myAdventureWorks.Tables) { /* Generating IF EXISTS and DROP command for tables */ StringCollection tableScripts =
myTable.Script(scriptOptions); foreach (string script in tableScripts) Console.WriteLine(script); /* Generating CREATE
TABLE command */ tableScripts = myTable.Script(); foreach (string script in tableScripts) Console.WriteLine(script); } }
private static void GenerateTableScriptWithDependencies(Server myServer) { Scripter scripter = new Scripter(myServer);
Database myAdventureWorks = myServer.Databases["AdventureWorks"]; Table myTable =
myAdventureWorks.Tables["EmployeeAddress", "HumanResources"]; /* Generate Scripts of table along with for all *
objects on which this table depends on */ ScriptingOptions scriptOptionsForDependendencies = new ScriptingOptions();
scriptOptionsForDependendencies.WithDependencies = true; /* DriAll will include all DRI objects in the generated script.
*/ scriptOptionsForDependendencies.DriAll = true; /* You can optionally can choose each DRI object separately as given
below */ //scriptOptionsForDependendencies.DriAllConstraints = true; //scriptOptionsForDependendencies.DriAllKeys =
true; //scriptOptionsForDependendencies.DriChecks = true; //scriptOptionsForDependendencies.DriClustered = true;
//scriptOptionsForDependendencies.DriDefaults = true; //scriptOptionsForDependendencies.DriForeignKeys = true;
//scriptOptionsForDependendencies.DriIndexes = true; //scriptOptionsForDependendencies.DriNonClustered = true;
//scriptOptionsForDependendencies.DriPrimaryKey = true; //scriptOptionsForDependendencies.DriUniqueKeys = true; /* If
you can use FileName to output generated script in a file * Note : You need to have access on the specified location*/
scriptOptionsForDependendencies.FileName = @"D:\TableScriptWithDependencies.sql"; StringCollection tableScripts =
myTable.Script(scriptOptionsForDependendencies); foreach (string script in tableScripts) Console.WriteLine(script); }
private static void GenerateTableScriptWithIndexes(Server myServer) { Scripter scripter = new Scripter(myServer);
Database myAdventureWorks = myServer.Databases["AdventureWorks"]; /* With ScriptingOptions you can specify
different scripting * options, for example to include IF NOT EXISTS, DROP * statements, output location etc*/
ScriptingOptions scriptOptions = new ScriptingOptions(); scriptOptions.ScriptDrops = true;
scriptOptions.IncludeIfNotExists = true; foreach (Table myTable in myAdventureWorks.Tables) { /* Generating IF EXISTS
and DROP command for tables */ StringCollection tableScripts = myTable.Script(scriptOptions); foreach (string script in
tableScripts) Console.WriteLine(script); /* Generating CREATE TABLE command */ tableScripts = myTable.Script();
foreach (string script in tableScripts) Console.WriteLine(script); IndexCollection indexCol = myTable.Indexes; foreach
(Index myIndex in myTable.Indexes) { /* Generating IF EXISTS and DROP command for table indexes */ StringCollection
indexScripts = myIndex.Script(scriptOptions); foreach (string script in indexScripts) Console.WriteLine(script); /*
Generating CREATE INDEX command for table indexes */ indexScripts = myIndex.Script(); foreach (string script in
indexScripts) Console.WriteLine(script); } } } private static void GenerateScriptWithoutCreatingObjectOnServer(Server
myServer) { /* Drop the database if it exists */ if (myServer.Databases["MyNewDatabase"] != null)
myServer.Databases["MyNewDatabase"].Drop(); /* Create database called, "MyNewDatabase" */ Database myDatabase =
new Database(myServer, "MyNewDatabase"); /* Output the database script on the console */ StringCollection DBScripts =
myDatabase.Script(); foreach (string script in DBScripts) Console.WriteLine(script); /* Create a table instance */ Table
myEmpTable = new Table(myDatabase, "MyEmpTable"); /* Add [EmpID] column to created table instance */ Column
empID = new Column(myEmpTable, "EmpID", DataType.Int); empID.Identity = true; myEmpTable.Columns.Add(empID);
/* Add another column [EmpName] to created table instance */ Column empName = new Column(myEmpTable,
"EmpName", DataType.VarChar(200)); empName.Nullable = true; myEmpTable.Columns.Add(empName); /* Add third
column [DOJ] to created table instance with default constraint */ Column DOJ = new Column(myEmpTable, "DOJ",
DataType.DateTime); DOJ.AddDefaultConstraint(); // you can specify constraint name here as well
DOJ.DefaultConstraint.Text = "GETDATE()"; myEmpTable.Columns.Add(DOJ); /* Add primary key index to the table */
Index primaryKeyIndex = new Index(myEmpTable, "PK_MyEmpTable"); primaryKeyIndex.IndexKeyType =
IndexKeyType.DriPrimaryKey; primaryKeyIndex.IndexedColumns.Add(new IndexedColumn(primaryKeyIndex,
"EmpID")); myEmpTable.Indexes.Add(primaryKeyIndex); /* Output the table script on the console */ StringCollection
TableScripts = myEmpTable.Script(); foreach (string script in TableScripts) Console.WriteLine(script); /* If you want to
create objects on the server you need call * create method or else objects will not be created on the server */
myDatabase.Create(); myEmpTable.Create(); } } }
Note
• If you have an application written in SQL-DMO and want to upgrade it to SMO, that is not possible, you will need
to rewrite your applications using SMO classes.
• SMO assemblies are installed automatically when you install Client Tools.
• Location of assemblies in SQL Server 2005 is C:\Program Files\Microsoft SQL Server\90\SDK\Assemblies folder.
• Location of assemblies in SQL Server 2008 is C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies
folder.
• SMO provides support for SQL Server 2000 (if you are using SQL Server 2005 SMO it supports SQL Server 7.0 as
well) but a few namespaces and classes will not be supported in prior versions.
• Scripter and ScriptingOptions classes are available in Microsoft.SqlServer.Smo assembly (in
microsoft.sqlserver.smo.dll) and Microsoft.SqlServer.Management.Smo namespace.
• User needs to have permissions on the objects in order to generate scripts for it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Sdk.Sfc;
namespace SQLScriptGenerationProgrammatically
{
class Program
{
static void Main(string[] args)
{
Server myServer = new Server(@"ARSHADALI-LAP\ARSHADALI");
try
{
//Using windows authentication
myServer.ConnectionContext.LoginSecure = true;
myServer.ConnectionContext.Connect();
//GenerateDBScript(myServer);
//GenerateTableScript(myServer);
//GenerateTableScriptWithDependencies(myServer);
//GenerateTableScriptWithIndexes(myServer);
GenerateScriptWithoutCreatingObjectOnServer(myServer);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (myServer.ConnectionContext.IsOpen)
myServer.ConnectionContext.Disconnect();
Console.WriteLine("Press any key to terminate....");
Console.ReadKey();
}
}
private static void GenerateDBScript(Server myServer)
{
Scripter scripter = new Scripter(myServer);
Database myAdventureWorks = myServer.Databases["AdventureWorks"];
StringCollection scriptCollection = scripter.Script(new Urn[] { myAdventureWorks.Urn });
foreach (string script in scriptCollection)
Console.WriteLine(script);
}
private static void GenerateTableScript(Server myServer)
{
Scripter scripter = new Scripter(myServer);
Database myAdventureWorks = myServer.Databases["AdventureWorks"];
/* With ScriptingOptions you can specify different scripting
* options, for example to include IF NOT EXISTS, DROP
* statements, output location etc*/
ScriptingOptions scriptOptions = new ScriptingOptions();
scriptOptions.ScriptDrops = true;
scriptOptions.IncludeIfNotExists = true;
foreach (Table myTable in myAdventureWorks.Tables)
{
/* Generating IF EXISTS and DROP command for tables */
StringCollection tableScripts = myTable.Script(scriptOptions);
foreach (string script in tableScripts)
Console.WriteLine(script);
/* Generating CREATE TABLE command */
tableScripts = myTable.Script();
foreach (string script in tableScripts)
Console.WriteLine(script);
}
}
private static void GenerateTableScriptWithDependencies(Server myServer)
{
Scripter scripter = new Scripter(myServer);
Database myAdventureWorks = myServer.Databases["AdventureWorks"];
Table myTable = myAdventureWorks.Tables["EmployeeAddress", "HumanResources"];
/* Generate Scripts of table along with for all
* objects on which this table depends on */
ScriptingOptions scriptOptionsForDependendencies = new ScriptingOptions();
scriptOptionsForDependendencies.WithDependencies = true;
/* DriAll will include all DRI objects in the generated script. */
scriptOptionsForDependendencies.DriAll = true;
/* You can optionally can choose each DRI object separately as given below */
//scriptOptionsForDependendencies.DriAllConstraints = true;
//scriptOptionsForDependendencies.DriAllKeys = true;
//scriptOptionsForDependendencies.DriChecks = true;
//scriptOptionsForDependendencies.DriClustered = true;
//scriptOptionsForDependendencies.DriDefaults = true;
//scriptOptionsForDependendencies.DriForeignKeys = true;
//scriptOptionsForDependendencies.DriIndexes = true;
//scriptOptionsForDependendencies.DriNonClustered = true;
//scriptOptionsForDependendencies.DriPrimaryKey = true;
//scriptOptionsForDependendencies.DriUniqueKeys = true;
/* If you can use FileName to output generated script in a file
* Note : You need to have access on the specified location*/
scriptOptionsForDependendencies.FileName = @"D:\TableScriptWithDependencies.sql";
StringCollection tableScripts = myTable.Script(scriptOptionsForDependendencies);
foreach (string script in tableScripts)
Console.WriteLine(script);
}
private static void GenerateTableScriptWithIndexes(Server myServer)
{
Scripter scripter = new Scripter(myServer);
Database myAdventureWorks = myServer.Databases["AdventureWorks"];
/* With ScriptingOptions you can specify different scripting
* options, for example to include IF NOT EXISTS, DROP
* statements, output location etc*/
ScriptingOptions scriptOptions = new ScriptingOptions();
scriptOptions.ScriptDrops = true;
scriptOptions.IncludeIfNotExists = true;
foreach (Table myTable in myAdventureWorks.Tables)
{
/* Generating IF EXISTS and DROP command for tables */
StringCollection tableScripts = myTable.Script(scriptOptions);
foreach (string script in tableScripts)
Console.WriteLine(script);
/* Generating CREATE TABLE command */
tableScripts = myTable.Script();
foreach (string script in tableScripts)
Console.WriteLine(script);
IndexCollection indexCol = myTable.Indexes;
foreach (Index myIndex in myTable.Indexes)
{
/* Generating IF EXISTS and DROP command for table indexes */
StringCollection indexScripts = myIndex.Script(scriptOptions);
foreach (string script in indexScripts)
Console.WriteLine(script);
/* Generating CREATE INDEX command for table indexes */
indexScripts = myIndex.Script();
foreach (string script in indexScripts)
Console.WriteLine(script);
}
}
}
private static void GenerateScriptWithoutCreatingObjectOnServer(Server myServer)
{
/* Drop the database if it exists */
if (myServer.Databases["MyNewDatabase"] != null)
myServer.Databases["MyNewDatabase"].Drop();
/* Create database called, "MyNewDatabase" */
Database myDatabase = new Database(myServer, "MyNewDatabase");
/* Output the database script on the console */
StringCollection DBScripts = myDatabase.Script();
foreach (string script in DBScripts)
Console.WriteLine(script);
/* Create a table instance */
Table myEmpTable = new Table(myDatabase, "MyEmpTable");
/* Add [EmpID] column to created table instance */
Column empID = new Column(myEmpTable, "EmpID", DataType.Int);
empID.Identity = true;
myEmpTable.Columns.Add(empID);
/* Add another column [EmpName] to created table instance */
Column empName = new Column(myEmpTable, "EmpName", DataType.VarChar(200));
empName.Nullable = true;
myEmpTable.Columns.Add(empName);
/* Add third column [DOJ] to created table instance with default constraint */
Column DOJ = new Column(myEmpTable, "DOJ", DataType.DateTime);
DOJ.AddDefaultConstraint(); // you can specify constraint name here as well
DOJ.DefaultConstraint.Text = "GETDATE()";
myEmpTable.Columns.Add(DOJ);
/* Add primary key index to the table */
Index primaryKeyIndex = new Index(myEmpTable, "PK_MyEmpTable");
primaryKeyIndex.IndexKeyType = IndexKeyType.DriPrimaryKey;
primaryKeyIndex.IndexedColumns.Add(new IndexedColumn(primaryKeyIndex, "EmpID"));
myEmpTable.Indexes.Add(primaryKeyIndex);
/* Output the table script on the console */
StringCollection TableScripts = myEmpTable.Script();
foreach (string script in TableScripts)
Console.WriteLine(script);
/* If you want to create objects on the server you need call
* create method or else objects will not be created on the server */
myDatabase.Create();
myEmpTable.Create();
}
}
}