Monday, June 1, 2009

Running SQL scripts in order from C# code

I have a folder of SQL scripts being compiled as embedded resources. They are named as such:

01 FirstTable.sql
02 SecondTable.sql
etc...

so that way I can run them in the order they need to be run in when say, resetting a database. The problem I ran into was getting the resources through reflection gave them to me in the wrong order... the second script was trying to be run first and it relies on the first script, so that obviously didn't work. Running Array.Sort() on the script list fixed this problem. The code ended up looking like:


public void Reset()
{
if (string.IsNullOrEmpty(ConnectionString) && Connection == null)
throw new Exception("Connection string and connection are null.");
else
{
if (Connection == null)
Connection = new MySqlConnection(ConnectionString);

Connection.Open();

MySqlCommand cmd = new MySqlCommand();
cmd.CommandText = "DROP DATABASE SystemsLogica; CREATE DATABASE SystemsLogica; USE SystemsLogica;";
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = Connection;

cmd.ExecuteNonQuery();

Assembly asm = Assembly.GetExecutingAssembly();

string[] scripts = asm.GetManifestResourceNames();
Array.Sort(scripts);

foreach (string file in scripts)
{
Stream res = asm.GetManifestResourceStream(file);
byte[] resbytes = new byte[res.Length];

res.Read(resbytes, 0, (int)res.Length);

Console.WriteLine(file);
Console.WriteLine("-----------------");
Console.WriteLine(Encoding.ASCII.GetString(resbytes));
Console.Write("\n\n\n");


using (cmd = new MySqlCommand())
{
cmd.CommandText = Encoding.ASCII.GetString(resbytes);
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection = Connection;

cmd.ExecuteNonQuery();
}

}

Connection.Close();
}
}


This works great in mono. This was just a test method, so there is no real error checking, so be careful.

3 comments:

  1. Wow, what verbose code for a simple task like that ... Try rewriting that in Scheme, Python, Ruby or JavaScript even - you'll be surprised how simple it can be done.

    ReplyDelete
  2. Would you mind showing me an example of using Python for this? It would be great to shorten this code, and I am sure the ideas behind doing it in Python can carry over.

    ReplyDelete
  3. Hey Brandon,

    unfortunately my Python isn't as good, so I whipped up a Ruby version. The MySQL connector isn't specifically great so I had to create a little helper method. Of course, one wouldn't want to use MySQL because of its lack of DDL transactions, anyway, but that's a different topic ;) So here you go (sorry, Blogger doesn't preserve indention):

    require 'rubygems'
    require 'mysql'
    require 'pathname'

    def mysql
    c = Mysql.connect('localhost', 'root')
    yield(c)
    c.close
    end

    mysql do |c|
    c.query('DROP DATABASE IF EXISTS SystemsLogica')
    c.query('CREATE DATABASE SystemsLogica')
    c.select_db('SystemsLogica')

    Pathname.glob('*.sql').sort.each do |sql|
    c.query(sql.read)
    end
    end

    ReplyDelete