Quantcast
Channel: Jonathan's Blog
Viewing all articles
Browse latest Browse all 12

Espresso Tip: Changing those nasty constraint names in Code First

$
0
0

When working with Entity Framework Code First, the database get’s generated for you… Duh!

You have control over several aspects of how this database get’s created.

First off are Data Annotations, such as Required, DefaultValue, ForeignKey, Key, etc.

Second is the Fluent Api which allows you to tap into the creation of the Database and remove all of those attributes off of your data classes.

You can specify the name of the database by passing a Name, or even a connectionString into the base constructor of your DbContext.

 

public class MyContext : DbContext
{
    public MyContext()
        base: ("MyDbName")
    {}
}

Lot’s of different control over the DB.

However, one thing that seems to be left out for now is explicitly naming your Primary Key constraints. By default, they come out looking something like… PK_USERS_FBC301?!?!?!? 

I think this is a default of SQL more than Code First’s fault or anything, but none the less it is kinda nasty.

The only way I have found to fix this problem is to tap into the Initialize method of the Context using either DropCreateDatabaseAlways, DropCreateDatabaseIfModelChanges, or by implementing your own version of IDatabaseInitializer. I did it like this…

 

// Somewhere in Global.asax
Database.SetInitializer(new DbInitializer());

// DbInitializer
public class DbInitializer : IDatabaseInitializer<MyContext>
{
    public void InitializeDatabase(MyDbcontext context)
        {
            if (context.Database.Exists())
            {
                if (!context.Database.CompatibleWithModel(true))
                {
                    string singleUserModeCommand =
                    string.Format("ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE",
                              context.Database.Connection.Database);
                    if (context.Database.Exists())
                    {
                        context.Database.ExecuteSqlCommand(singleUserModeCommand);
                        context.Database.Delete();
                    }
                    context.Database.Create();
                    Seed(context);
                }

            }
            else
            {
                context.Database.Create();
                Seed(context);
            }
        }

        protected void Seed(MyDbContext context)
        {
            FixPrimaryKeyConstraints(context);
        }

        private void FixPrimaryKeyConstraints(MyDbContext context)
        {
            const string sql =
                @"  SET NOCOUNT on 
                    DECLARE @cnt int
                    DECLARE @table varchar(128)
                    DECLARE @cmd varchar(500) 
                    --create table #rowcount (tablename varchar(128), rowcnt int)
                    DECLARE tables cursor for
                    SELECT table_name from information_schema.tables
	                    WHERE table_type = 'base table'
	                    ORDER BY table_name
                    OPEN tables
                    FETCH NEXT FROM tables into @table
                    WHILE @@fetch_status = 0
                    BEGIN
	                    DECLARE @TableName NVARCHAR(128)
	                    DECLARE @IndexName NVARCHAR(128)
	                    DECLARE @OldName NVARCHAR(128)
	                    DECLARE @NewName NVARCHAR(128)
	                    SELECT  @TableName = @table

	                    SELECT  @IndexName = C.CONSTRAINT_NAME
	                    FROM    INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ,INFORMATION_SCHEMA.KEY_COLUMN_USAGE C
	                    WHERE   pk.TABLE_NAME = @TableName
		                    AND   CONSTRAINT_TYPE = 'PRIMARY KEY'
		                    AND   C.TABLE_NAME = PK.TABLE_NAME
		                    AND   C.CONSTRAINT_NAME = PK.CONSTRAINT_NAME

	                    SELECT  @OldName = @TableName + '.' + @IndexName
	                    SELECT  @NewName = 'PK_' + @TableName
	                    exec sp_rename @OldName, @NewName, 'INDEX'
                      FETCH NEXT FROM tables into @table
                    END
                    CLOSE tables 
                    DEALLOCATE tables";

            context.Database.ExecuteSqlCommand(sql);
        }
}

This file does a few things. First it detects changes to the DB, forces a drop if neccessary, then runs the seed.
The seed then calls the FixPrimaryKeyConstraints which loops over all of the tables in the Database and renames them PK_TableName.

Hope you enjoyed this Espresso Tip!


Viewing all articles
Browse latest Browse all 12

Trending Articles