Introduction
When most developers develop database code (including tables, views, stored procedures and functions, they tend to develop in a development environment and then migrate those changes later to other servers (staging, production, whatever). While some of us are good about keeping track of those changes, the majority of us are not.
Red-Gate Software offers a tool, SQL Compare to compare the schema of two databases and show them to the user. This tool is not inexpensive, but it works very well.
This article provides the basic functionality used to do the same thing as SQL Compare, at a fraction of the price.
Background
SQL 2000 and above uses a series of system tables to store the definition of all objects in a database. The important objects (for this project) are:
sysobjects
- Stores a list of all objects in the database (MSDN Reference) syscolumns
- Stores a list of the columns of the objects in the database (MSDN Reference) syscomments
- Stores the definition of objects in the database (MSDN Reference)
Using the Code
The code is broken into two projects:
DatabaseCompare
(the Winforms project)DatabaseCompare.Domain
(the database access project)
There is nothing ground breaking in the Winforms project. I did use a couple delegates to make the UI more responsive when performing long tasks.
The Domain
project contains classes that actually perform the work in gathering the schema of a database and comparing the two databases.
The code is fairly self explanatory, the main entry points to the Domain
code are Database.TestConnection()
, Database.LoadObjects()
, and Database.CompareTo()
.
Points of Interest
Longer function/stored procedure/view definitions are maintained in multiple rows in the syscomments
database and must be retrieved like so:
using( SqlCommand command = conn.CreateCommand() )
{
command.CommandText = "select text from syscomments where id=@id";
command.Parameters.Add( "@id", this.Id );
using ( SqlDataReader reader = command.ExecuteReader() )
{
while( reader.Read() )
textDefinition += reader.GetString( 0 ).Trim().ToLower();
}
}
This code does not create drop/create scripts for tables, but that is a fairly trivial exercise for you to do if you need that functionality.
Using the sysdepends
table, you could determine what the dependencies for the objects are, in case you are creating CREATE
scripts and need to know what to create first.