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!




Pingback: The Morning Brew - Chris Alcock » The Morning Brew#1007