views:

358

answers:

3

What is the recommended method for executing a SQL Server script from within a .NET application and why?

I'm in process of creating an application we can run from our installer to handle upgrading our database when a prior version of our application is installed. The database has a version table that I can programatically access and determine which upgrade scripts to run to get the database upgraded. It makes sense for me to embed this in an application that our installer can just call to do the upgrade.

I am looking for how best to execute the appropriate upgrade scripts. Searching the web I've seen recommendations for splitting a script by "GO" statements, and using SqlCommand.ExecuteNonQuery(). I've also seen recommendations for using SQL Server Management Objects (SMO).

I'm looking for advice on the pros/cons of the various ways to execute these scripts from within a .NET application.

+1  A: 

I have had consistent results using a System.Diagnostics.Process and calling into OSQL.exe. its made for a sql file....

I created a temporary file where i wrote my embedded sql file, had OSQL execute it, then cleaned it up.

    process.StartInfo = new System.Diagnostics.ProcessStartInfo();
    process.StartInfo.FileName = OSQLpath;
    process.StartInfo.UseShellExecute = false;
    ...
    if (!System.IO.Directory.Exists(workingDirectory))
                        System.IO.Directory.CreateDirectory(workingDirectory);
    ...
    StringBuilder sbArgs = new StringBuilder();

    sbArgs.Append("-S ").Append(_serverName);
    sbArgs.Append(" -d ").Append(_databaseName);
    sbArgs.Append(" -E");
    sbArgs.Append(" -i ").Append("\"").Append(inputSQLFilePath).Append("\""); // input file
    sbArgs.Append(" -o ").Append("\"").Append(System.IO.Path.Combine(workingDirectory, String.Format("osqloutput_{1}_{0}.txt", fileUnique, fileName))).Append("\""); // output file

    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.RedirectStandardError = true;

    process.StartInfo.Arguments = sbArgs.ToString();
    process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    process.StartInfo.CreateNoWindow = true;

...

    System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.WaitCursor;
    process.Start();
    process.WaitForExit();
Jason w
There are issues with this technique in that you have to parse I/O from the external executable. Using a .NET API make most sense.
BrianLy
+2  A: 

Although it may not specifically meet your needs to be run from within a .NET application, sqlcmd is well-suited (and designed) for this process. By implementing the ability parse & run a SQL Script, you are duplicating the tool functionality. sqlcmd is available in a standalone installer that could be bundled with your application.

If you choose to use the linked SqlCommand.ExecuteNonQuery() solution, it will be more memory efficient for large scripts to read the script into a smaller buffer searching for the "GO" statement, "instead of all-at-once".

Cadaeic
+1  A: 

The best method would be any method that meets all functional and nonfunctional restraints.

What kind of speed do you need, is there any problem with the current situation What is your backup/failure strategy

I would probably use the SqlCommand.ExecuteNonQuery() because its a part of the .net runtime that needs no extra installation of applications the user might not need.

From your question I presume there is an existing application with lots of embedded query string. I would try to get the into a repository of some kind that automatically places them on the server (as a stored procedure) and inside your code.

Don't be afraid of simple text files or other config files with query's.

Barfieldmv
I'm leaning towards SqlCommand.ExecuteNonQuery(). We have a version table in the DB, and will have defined scripts to upgrade between versions, which will all be under source code control. The application this is for has a home-grown ORM, I'm specifically working on the installer for the app.
Steve Wranovsky
That technique seems like your best bet, you could even wrap the SQL statements in a set of transactions and get step-by-step confirmations of whether it has been applied correctly, rollback on failure etc.
BrianLy