Reputation: 6249
does anybody know how to spedify exact .mdf/.log file location during EF CodeFirst database initialization?
For a debug and testing scenario (but specifying exact DB files location can be useful in production as well), I'd like to re-deploy database during application start-up, but also I'd like to create DB files on a specific location (e.g. secong hard drive).
public class MyCustomInitialized : DropCreateDatabaseAlways<MyContext>
{
public override void InitializeDatabase(MyContext context)
{
if (context.Database.Exists())
{
// set the database to SINGLE_USER so it can be dropped
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "ALTER DATABASE [" + context.Database.Connection.Database + "] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
// drop the database
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "USE master DROP DATABASE [" + context.Database.Connection.Database + "]");
// Doesn't work yet
var directoryPath = ConfigurationManager.AppSettings["DatabaseDirectoryPath"];
var fileName = ConfigurationManager.AppSettings["DatabaseFileName"];
if(!Database.Exists()) {
var qry = string.Format(
"USE master CREATE DATABASE {0}" + Environment.NewLine +
"ON PRIMARY" + Environment.NewLine +
"( NAME = {0}, FILENAME = '{1}')" + Environment.NewLine +
"LOG ON" + Environment.NewLine +
"( NAME = {2}, FILENAME = '{3}')" + Environment.NewLine
, this.Database.Connection.Database,
Path.Combine(directoryPath, fileName + ".mdf"),
this.Database.Connection.Database + "_log",
Path.Combine(directoryPath, fileName + "_log.ldf"));
// -- EXCEPTION HERE,
Database.ExecuteSqlCommand(qry);
Database.ExecuteSqlCommand("USE " + this.Database.Connection.Database);
}
base.InitializeDatabase(context);
}
}
The exeption I get:
Cannot open database "DatabaseName" requested by the login. The login failed. Login failed for user 'SomeUser'. A severe error occurred on the current command. The results, if any, should be discarded.
If the database can be created by EF during initialization, how this initialization can be overriden?
Thanks, Tom
Upvotes: 2
Views: 606
Reputation: 107237
I was able to get the below working, in both the database exists and non-exists scenarios, however, there is one issue in that the Code First table creation isn't being triggered (i.e. this is only a partial solution - there is still a step needed to actually get EF to create the Code First tables).
(My context was called Model1
)
public class MyCustomInitialized : DropCreateDatabaseAlways<Model1>
{
public override void InitializeDatabase(Model1 context)
{
if (context.Database.Exists())
{
// set the database to SINGLE_USER so it can be dropped
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction,
"ALTER DATABASE [" + context.Database.Connection.Database +
"] SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
// drop the database
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction,
"USE master DROP DATABASE [" + context.Database.Connection.Database + "]");
}
var directoryPath = @"c:\temp";
var fileName = "Foo";
var qry = string.Format(
"USE master CREATE DATABASE {0}" + Environment.NewLine +
"ON PRIMARY" + Environment.NewLine +
"( NAME = {0}, FILENAME = '{1}')" + Environment.NewLine +
"LOG ON" + Environment.NewLine +
"( NAME = {2}, FILENAME = '{3}')" + Environment.NewLine
, context.Database.Connection.Database,
Path.Combine(directoryPath, fileName + ".mdf"),
context.Database.Connection.Database + "_log",
Path.Combine(directoryPath, fileName + "_log.ldf"));
using (var conn = new SqlConnection(@"data source=.\SQLExpress;initial catalog=master;integrated security=True;"))
using (var cmd = new SqlCommand(qry, conn))
{
conn.Open();
cmd.ExecuteNonQuery();
}
-- TODO trigger the table creation
this.Seed(context);
context.SaveChanges();
}
}
Some notes:
Database
belongs to the context"Cannot open database \"FOO\" requested by the login"
. I would also consider moving the DROP of the Context connection into a master
connection.Calling
base.InitializeDatabase(context);
Causes the Db to be dropped and recreated because of the DropCreateDatabaseAlways
strategy which includes:
context.Database.Delete();
context.Database.Create(DatabaseExistenceState.DoesNotExist);
So hence
-- missing something here, viz creating the tables
this.Seed(context);
context.SaveChanges();
Upvotes: 1