Summary
SPGen is a simple Windows application which can generate the TSQL code for an INSERT
or UPDATE
Microsoft SQL Stored Procedures. Point it at a table, click the generate button and the code is generated for you.
The article covers some basic SQLDMO (SQL Database Management Object) methods and provides a slim .NET wrapper class around SQLDMO to help you in using SQLDMO.
1. A screenshot of SPGen in action with a generated Stored Procedure in the main text box
Introduction
Writing the basics of Stored Procedures is mind numbing at best, even for DBAs. Megan Forbes, myself and a few others got into a heated rant about Microsoft SQL Server Enterprise Manager and it's extreme lack of SP tools and management. I decided to write a very simple app which takes away the drudge of typing in all the base code for an SP. When you are faced with a table of 50 fields and the need to create a simple UPDATE
or INSERT
SP, declaring all those parameters can be akin to agreeing to be the designated driver for the office Christmas party, i.e. deadly boring.
Using the application
Extract the downloaded demo zip, or re-compile the project, and run the executable.
- SPGen starts up and lists all locally registered SQL Servers in the top left drop down list
- Select, or type in, the SQL Server you want to connect to
- Enter in the User Name and Password for the SQL Server. If there is no Password needed then just leave the Password field untouched
- Click the Connect button
- SPGen will now attempt to connect to the specified SQL Server and list all the Databases
- Once the Databases are listed, expand the Database you wish to work with
- SPGen will now list all the Tables within the expanded Database
- Now expand the Table you wish to generate an SP for
- There will be two options;
UPDATE
orINSERT
. Click the one you want - SPGen will now attempt to retrieve the columns for the Table (but not display them) and generate the specified SP type
- Once generated the code is placed in the text box on the right and you can cut & paste that code into Microsoft SQL Enterprise Manager, or Microsoft SQL Server Query Analyzer
That is the extent of SPGen's functionality. You can generate SPs for other Tables, without having to re-connect, or you can connect to another SQL Server and generate SPs for that.
SQLDMOHelper
SQLDMOHelper
is a simple class which returns basic information about a SQL Server to the caller. Really it just wraps up the common methods I needed from SQLDMO into easy to use .NET methods which return easily usable data. To this end it only returns data and does not provide any methods to save changes to a SQL Server, yet.
Using SQLDMO in your .NET app is actually very simple. All you need to do is add a reference to the Microsoft SQLDMO Object Library COM object in your project. You can then utilise SQLDMO methods with the interopped SQLDMO namespace. All very simple thanks to .NET.
Property: public Array RegisteredServers
This property returns a one-dimensional string array containing the names of all registered SQL Servers in the local domain.
SQLDMO provides a class called ApplicationClass
which you can use to gather this list, like so;
ArrayList aServers = new ArrayList();
SQLDMO.ApplicationClass acServers = new SQLDMO.ApplicationClass();
for (int iServerGroupCount = 1;
iServerGroupCount <= acServers.ServerGroups.Count;
iServerGroupCount++)
for (int iServerCount = 1;
iServerCount <= acServers.ServerGroups.Item(
iServerGroupCount).RegisteredServers.Count;
iServerCount++)
aServers.Add(acServers.ServerGroups.Item
(iServerGroupCount).RegisteredServers.Item(iServerCount).Name);
return aServers.ToArray();
Quite simply a new instance of ApplicationClass
is created. Then a for
loop runs through each ServerGroups
returned and then in the second for
loop adds each RegisteredServer
name to the aServers
ArrayList
. aServers
is then returned to the caller to be consumed.
ArrayList
really makes working with un-known length arrays very easy. You can basically redimension the array on the fly and then once you are finished use the ToArray
method to return a valid Array
.
Property: public Array Databases
Databases
is a property which returns, as the name suggest, a one-dimensional string array of all Databases in a specified SQL Server.
ArrayList aDatabases = new ArrayList();
foreach(SQLDMO.Database dbCurrent in Connection.Databases)
aDatabases.Add(dbCurrent.Name);
return aDatabases.ToArray();
A simple foreach
loop is run against the SQLDMO.Databases
collection which is returned from Connection.Databases
.
Connection
is a property of SQLDMOHelper
which provides a SQLDMO Server connection. You need to use the Connect
method to set the Connection
property up. Also remember to use the DisConnect
method to, wait for it, disconnect the connection.
Databases
then returns the string array of Database names for your app to use.
Property: public Array Tables
Looks familiar, doesn't it? It is. The Tables
property returns a one-dimensional string array of all Table names in a specified Database.
ArrayList aTables = new ArrayList();
SQLDMO.Database dbCurrent = (SQLDMO.Database)Connection.Databases.Item(
this.Database, Connection);
foreach(SQLDMO.Table tblCurrent in dbCurrent.Tables)
aTables.Add(tblCurrent.Name);
return aTables.ToArray();
Property: public SQLDMO.Columns Fields
The Fields
property however is a bit different. Instead of returning a one-dimensional string array it returns a SQLDMO.Columns
collection which provides a full range of details on all columns (fields) within a table.
The code though is even simpler than before as we are really just returning what SQLDMO provides and not translating it at all:
SQLDMO.Database dbCurrent = (SQLDMO.Database)
Connection.Databases.Item(this.Database, Connection);
SQLDMO.Table tblCurrent = (SQLDMO.Table)
dbCurrent.Tables.Item(this.Table, Connection);
return tblCurrent.Columns;
Columns
is a collection of SQLDMO.Column
objects which contain various properties and methods for working on a field in a table. In SPGen only Name
, DataType
and Length
are used, but there are many more.
Properties: string ServerName
, UserName
, Password
, DataBase
and Table
These four properties of SQLDMOHelper
are simply strings which hold what SQL Server, user name, password, database and table respectively the methods of SQLDMOHelper
should work on. For instance Databases
requires just ServerName
, UserName
and Password
to be filled in to work. To use Fields
though you also need Database
and Table
filled in so that Fields
knows what to work on.
StoredProcedure
The StoredProcedure
class provides just one method at the moment, Generate
. This, finally, is the heart of SPGen and provides the functionality for returning valid Stored Procedure code.
Method: public string Generate
Parameters:
StoredProcedureTypes sptypeGenerate
Anenum
indicating the type of Stored Procedure to generate.StoredProcedureTypes.INSERT
andStoredProcedureTypes.UPDATE
are currently valid choicesSQLDMO.Columns colsFields
TheColumns
collection to use in the generation of the Stored Procedurestring sTableName
The name of the Table theINSERT
orUPDATE
will affect
The code within Generate
is pretty straight forward and consists largely of a StringBuilder
being used to construct the Stored Procedure. On that note I found the AppendFormat
method of StrinbBuilder
to be highly effective for this kind of work.
Take this code for instance: sParamDeclaration.AppendFormat(" @{0} {1}", new string[]{colCurrent.Name, colCurrent.Datatype});
. Without the AppendFormat
method one would have to do the following: sParamDeclaration += " @" + colCurrent.Name + " " + colCurrent.Datatype;
This latter way is terrible to debug and hard to understand when there is a whole page of similar code. The format functionality of StringBuilder
(and just String
itself) makes for much more manageable and understandable string manipulation.
StringBuilder
also is faster than using sSample += "Not in kansas, " + sName + ", anymore";
, especially when performing many string appends. Thanks to Tom Archer's fantastic sample chapter on using String
in .NET, I certainly learnt a lot from it.
One other slight item of interest in the Generate
method is this:
if (
colCurrent.Datatype == "binary" ||
colCurrent.Datatype == "char" ||
colCurrent.Datatype == "nchar" ||
colCurrent.Datatype == "nvarchar" ||
colCurrent.Datatype == "varbinary" ||
colCurrent.Datatype == "varchar")
sParamDeclaration.AppendFormat("({0})", colCurrent.Length);
Basically in TSQL you must only declare the length of a parametre if it is one of the above data types. If you for instance try @NameFirst int(4)
in TSQL you will get back an error as you may not declare the length of an int
data type. At present I know of no way to programatically detect which data types must and must not have length declarations, therefore I have used the cumbersome if
block you see above. I was hoping that SqlDbType
would provide the neccesary information, but it does not, rendering it slightly less useful.
Apart from the the method is as stated mainly a big string manipulation method which takes in the provided fields, loops through them and returns a Stored Procedure of the type specified.
As I find more areas to automate in regards to Stored Procedures I hope to add new methods and helpers to this class.
Other Titbits
There is not much more to say or explain about SPGen, it really is a simple app. However following are two basically unrelated but still interesting titbits that you may find useful.
app.config
I have finally found a use for the app.config file beyond the usual. With SPGen you can open up app.config and modify the ServerName
, UserName
and Password
application keys. SPGen will then read them in when the app starts and pre-fill the fields for you. This way if you have an often used SQL Server you can just fire up SPGen and hit connect without having to re-type the details in each time.
Obviously you want to be careful with the Password
key especially, but I put it in with full confidence nobody would let their app.config file go wandering.
Code wise it is really quite simple:
NameValueCollection settingsAppSettings =
(NameValueCollection)ConfigurationSettings.AppSettings;
if (settingsAppSettings["ServerName"] != null &&
settingsAppSettings["ServerName"] != "")
{
selServers.Text = settingsAppSettings["ServerName"];
dmoMain.ServerName = settingsAppSettings["ServerName"];
}
First I create a NameValueCollection
collection, simply to make working with the configuration settings easier (i.e. instead of having to type ConfigurationSettings.AppSettings["key"]
each time.) Then the code checks if there is a specified key value (I did not want the "Select Server" message being removed when there was no value) and then it sets the input field up to the value.
Nothing fancy, but it gives SPGen a small measure of customisation and gives your fingers a rest. By the way, on release build of SPGen app.config is automatically renamed to SPGen.exe.config, that is the file you need to edit to put in your SQL Server details.
TextBox PasswordChar
The PasswordChar
property of the TextBox
is pretty simple. You give it a char
value that you want displayed instead of the actual text, e.g. *
.
However, what if you want to reset that same TextBox
so that it no longer masks the input? In SPGen I needed to do this as I, maybe wrongly, did not include labels for my input fields. MSDN provides a clue, but does not go on to show you exactly how. After a bit of stumbling around I figured it out;
char chResetPassword = (char)0;
txtPassword.PasswordChar = chResetPassword;
So you create a char
of 0 (zero) and then assign that to the PasswordChar
property.
It is quite obvious once you figure it out, but can be annoying before that.
Possible Improvements & Bugs
- Allow the app to generate SPs from a
SELECT
query instead of just a Table selection - Allow the app to actually insert the SP into the database, saving you from having to cut & paste
Conclusion
Stored Procedures are very powerful but can be a tedious affair when multiple parameteres are required. Used in conjunction with Llewellyn Pritchard's DBHelper app though, you will have an end-to-end solution to working with Stored Procedures in an easy and fast manner.
SQLDMO is also a useful means of discovering and exploring SQL Servers and Databases. The main problem, in a .NET environment though, is that SQLDMO must be used through COM Interop, which is not an optimum situation. Hopefully in the near future a .NET SQLDMO will be released (though if you care to shed some light on how SQLDMO works I would be happy to write my own SQLDMO.NET class.)
If you have any ideas as to how to improve the app then please speak up.
License
This article, along with any associated source code and files, is licensed under The MIT License
About the Author
Paul Watson Member | Paul is an internet developer living in Waterford, Ireland though home is still South Africa. He believes in self-taught programming skills, standards based thinking and in the power of the common man. Oh, and he loves photography. Make sure you don't get caught in the corner of a party when he has that photographic gleam in his eye. And if you were wondering about that bed-head photograph, wonder no longer...
|