views:

285

answers:

3

As part of a ASP.NET MVC project I'm working on, I'll be working with SQL Server 2008 Express.

I'm not sure how I should go about having a version-controllable (I'm using Mercurial) way of recreating the database.

Ideally it should be run every time I perform a build in Visual Studio 2008.

EDIT 1: In response to couple of the answers, I'm using Visual Studio 2008 Professional Edition, which I have recieved via the Dreamspark program.

A: 

Are you using Visual Studio Team Suite or Visual Studio Developer Edition? If so, Visual Studio Database Edition is free, and a fantastic way to manage your database schema. Has about all the features you could want.

Randy

Randy Minder
+2  A: 

Have a look at Visual Studio Team System 2008 Database Edition GDR (Or DataDude)

This allows you to store and work with database schemas and artefacts (tables, procedures, triggers... pretty much everything). It also allows comparing one schema against another, or against an instance of a database and will generated change/deployment scripts.

There is support for reference data too (although this isn't great at this stage in the products life).

There is also integration with MSBuild - I'm using this on a large project now, every time we do a build, a schema file is generated which we then use to actually generate the scripts to apply to a given database (Using VSDBCMD.EXE). We don't currently automatically push these changes out but doing so is not too difficult.

David Hall
Unfortunately I only have access to the Visual Studio 2008 Professional Edition, and this doesn't seem to work for my edition.
Alastair Pitts
+2  A: 

There are a couple ways of accomplishing this depending on some of your project specifics. We have .sql files that when executed recreate the database. This allows the scripts to go into your source control and be versioned just like everything else. It also allows for change scripts to be added once a product is in production.

We use this to drop all the objects in our database:

private static void DropDatabaseObjects()
    {
        var dropDatabaseObjects =
            @"
                    /* Drop all non-system stored procs */
                    DECLARE @name VARCHAR(128)
                    DECLARE @constraint VARCHAR(254)
                    DECLARE @SQL VARCHAR(254)
                    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'P' AND category = 0 ORDER BY [name])
                    WHILE @name is not null
                    BEGIN
                        SELECT @SQL = 'DROP PROCEDURE [dbo].[' + RTRIM(@name) +']'
                        EXEC (@SQL)
                        PRINT 'Dropped Procedure: ' + @name
                        SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'P' AND category = 0 AND [name] > @name ORDER BY [name])
                    END

                    /* Drop all views */
                    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'V' AND category = 0 ORDER BY [name])
                    WHILE @name IS NOT NULL
                    BEGIN
                        SELECT @SQL = 'DROP VIEW [dbo].[' + RTRIM(@name) +']'
                        EXEC (@SQL)
                        PRINT 'Dropped View: ' + @name
                        SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'V' AND category = 0 AND [name] > @name ORDER BY [name])
                    END

                    /* Drop all functions */
                    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0 ORDER BY [name])
                    WHILE @name IS NOT NULL
                    BEGIN
                        SELECT @SQL = 'DROP FUNCTION [dbo].[' + RTRIM(@name) +']'
                        EXEC (@SQL)
                        PRINT 'Dropped Function: ' + @name
                        SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0 AND [name] > @name ORDER BY [name])
                    END                        

                    /* Drop all Foreign Key constraints */
                    SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)
                    WHILE @name is not null
                    BEGIN
                        SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
                        WHILE @constraint IS NOT NULL
                        BEGIN
                            SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT ' + RTRIM(@constraint)
                            EXEC (@SQL)
                            PRINT 'Dropped FK Constraint: ' + @constraint + ' on ' + @name
                            SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
                        END
                    SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME)
                    END

                    /* Drop all Primary Key constraints */
                    SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)
                    WHILE @name IS NOT NULL
                    BEGIN
                        SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
                        WHILE @constraint is not null
                        BEGIN
                            SELECT @SQL = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT ' + RTRIM(@constraint)
                            EXEC (@SQL)
                            PRINT 'Dropped PK Constraint: ' + @constraint + ' on ' + @name
                            SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME)
                        END
                    SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'PRIMARY KEY' ORDER BY TABLE_NAME)
                    END

                    /* Drop all tables */
                    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 ORDER BY [name])
                    WHILE @name IS NOT NULL
                    BEGIN
                        SELECT @SQL = 'DROP TABLE [dbo].[' + RTRIM(@name) +']'
                        EXEC (@SQL)
                        PRINT 'Dropped Table: ' + @name
                    SELECT @name = (SELECT TOP 1 [name] FROM sysobjects WHERE [type] = 'U' AND category = 0 AND [name] > @name ORDER BY [name])
                    END";
        using (var connection = new SqlConnection(GetConnectionStringFromHibernateConfiguration("hibernate.cfg.xml")))
        using (var command = new SqlCommand(dropDatabaseObjects, connection))
        {
            connection.Open();
            command.ExecuteNonQuery();
            connection.Close();
        }
    }

We use this to recreate our database (assuming the dbScriptFolder contains .sql files that will create all the tables, views, stored procs, etc):

private static void RecreateDatabase()
    {
        var directoryInfo = new DirectoryInfo(ConfigurationManager.AppSettings["dbScriptFolder"]);
        using (var connection = new SqlConnection(GetConnectionStringFromHibernateConfiguration("hibernate.cfg.xml")))
        {
            connection.Open();
            foreach (var fileInfo in directoryInfo.GetFiles())
            {
                if (fileInfo.Extension == ".sql")
                {
                    var script = ReadFromFile(fileInfo);
                    var server = new Server(new ServerConnection(connection));
                    server.ConnectionContext.ExecuteNonQuery(script);
                }
            }
            connection.Close();
        }
    }

These methods get called in a base testfixture method for when we run our integration tests so we know we're working with our database in a known state.

If you're looking to do this as part of a build script, have a look at the Tarantino project here and here

Chris Conway
I'm marking this as the answer as this is basically how i've done it. this blog post I found was quite handy as well: http://blog.reamped.net/post/2008/05/Using-Database-Projects-for-Visual-Studio.aspx
Alastair Pitts