views:

102

answers:

1

I use migrations a lot (only MySQL) and since SubSonic Migrations only allows to define the parent and the master column in CreateForeignKey, I cannot define the update/delete actions in a FK Relation.

However there a quite a number of scenarios where I, for instance, need to define a FK relation where, if I delete the parent record, all records in the child table should be set to null (default would be to restrict the delete).

I use a little function that does this for me. However since this is totally MySQL specific, and it breaks the idea that stands behand migrations (to be DB independent), I decided not to provide a patch for this. So I post the code snippet here.

But if someone needs this, too. Feel free to use it.
There is only one drawback: Since sonic.exe reads the code file and complies it on the fly you have to paste the code into every migration where you use it.

A: 

Here's a sample migration where I use this. In the down method you can just use the existing "DropForeignKey(...)" method, since the naming stays the same.

using System;
using System.Collections.Generic;
using System.Text;
using SubSonic;

namespace MyNameSpace.Migrations
{

    public class Migration001 : Migration
    {

        public override void Up()
        {
            TableSchema.Table parent = GetTable("parent");
            TableSchema.Table child = GetTable("child");

            CreateForeignKeyMySQL(parent.GetColumn("id"), child.GetColumn("parent_id"),
                CreateForeignKeyAction.SetNull, CreateForeignKeyAction.Restrict);

            base.Up();
        }

        public override void Down()
        {
            DropForeignKey(parent.GetColumn("id"), child.GetColumn("parent_id"));

            base.Down();
        }

        #region foreign key helper function

        public enum CreateForeignKeyAction
        {
            Cascade,
            Restrict,
            SetNull,
            NoAction
        }

        private String CreateForeignKeyActionValue(CreateForeignKeyAction action)
        {
            switch (action)
            {
                case CreateForeignKeyAction.Cascade:
                    return "CASCADE";
                case CreateForeignKeyAction.Restrict:
                    return "RESTRICT";
                case CreateForeignKeyAction.SetNull:
                    return "SET NULL";
                case CreateForeignKeyAction.NoAction:
                    return "NO ACTION";
                default:
                    return "CASCADE";
            }
        }

        public void CreateForeignKeyMySQL(
            TableSchema.TableColumn oneTable, TableSchema.TableColumn manyTable,
            CreateForeignKeyAction onDelete, CreateForeignKeyAction onUpdate)
        {

            String sqlAppend = String.Format(" ON DELETE {0} ON UPDATE {1}",
                CreateForeignKeyActionValue(onDelete), CreateForeignKeyActionValue(onUpdate));

            SubSonic.MySqlGenerator generator = new SubSonic.MySqlGenerator(null);
            String sqlCommand =
                System.Text.RegularExpressions.Regex.Replace(
                    generator.BuildForeignKeyStatement(oneTable, manyTable), ";?$", sqlAppend
                );

            Execute(sqlCommand);
        }

        #endregion

    }

}
SchlaWiener