以编程方式从头开始在任意位置

时间:2015-08-18 16:28:07

标签: c# sql-server database entity-framework

我正在使用一个使用SQL Server Express / LocalDB的简单桌面应用。我是一个任意非特权位置的数据目录,在那里我想创建一个数据库文件。我最初创建了数据库,并为EF生成了一个模型供使用;现在我想使用该模型在任何我想要的地方重新创建数据库。

我发现各种帖子类似,但它们似乎是为了测试目的而通过开始使用的上下文删除和重新创建现有数据库。我想从一个空目录开始。

使用here中代码的摘录,我能够在磁盘上物理创建数据库文件,使用SQL语句创建新的.mdf和.ldf文件。但他们没有架构;如果我从.mdf文件中启动一个上下文实例,然后尝试计算表中的行数,我会抛出异常,因为该表不存在。

如果我尝试调用ctx.Database.Create(),那么我会收到数据无法创建的错误,因为它已经存在。它当然是这样,只是没有表格。

如果我最初不使用原始SQL查询来创建新的空数据库,我尝试按如下方式创建上下文,其中filespec指向有效目录中不存在的.mdf文件, .Create()总是抛出异常"数据库''无法创建,因为它已经存在"

string connectionString
        = "Data Source=(LocalDB)\\v11.0;AttachDbFilename="
        + fileSpec;

EventsListDBEntities ctx = new EventsListDBEntities();
ctx.Database.Connection.ConnectionString = connectionString;
ctx.Database.Create();
ctx.Database.Initialize(true);

如何让EF在我的空数据库中创建表,或从头开始创建文件?

2 个答案:

答案 0 :(得分:1)

请尝试使用以下内容:

string connectionString
        = "Data Source=(LocalDB)\\v11.0;AttachDbFilename="
        + fileSpec;

EventsListDBEntities ctx = new EventsListDBEntities();
ctx.Database.Connection.ConnectionString = connectionString;
ctx.Database.CreateIfNotExists(); // Change this line.
ctx.Database.Initialize(true);

https://msdn.microsoft.com/en-us/library/system.data.entity.database.createifnotexists%28v=vs.113%29.aspx#M:System.Data.Entity.Database.CreateIfNotExists

答案 1 :(得分:0)

经过大量的实验,这里的代码我已经完成了这项工作。

string connectionString
      = "Data Source=(LocalDB)\\v11.0;AttachDbFilename="
      + fileSpec + ";database=EventsListDB";

/* We can't go straight into the context and create the DB because 
 * it needs a connection to "master" and can't create it. Although this
 * looks completely unrelated, under the hood it leaves behind something
 * that EF can pick up and use- and it can't hurt to delete any references 
 * to databases of the same name that may be lurking in other previously
 * used directories.
 */

SqlConnectionStringBuilder masterCSB = new SqlConnectionStringBuilder(connectionString);
masterCSB.InitialCatalog = "master";
masterCSB.AttachDBFilename = "";

using (var sqlConn = new SqlConnection(masterCSB.ToString()))
{
    sqlConn.Open();
    using (var cmd = sqlConn.CreateCommand())
    {
        bool done = false;
        int attempt = 0;
        do
        {
            try
            {
                cmd.CommandText =
                    String.Format(
                        "IF EXISTS (Select name from sys.databases " + 
                        "WHERE name = '{0}') " +
                        "DROP DATABASE {0}", "EventsListDB");
                cmd.ExecuteNonQuery();
                done = true;
            }
            catch (System.Exception ex)
            {
                /* We sometimes get odd exceptions that're probably because LocalDB hasn't finished starting. */
                if (attempt++ > 5)
                {
                    throw ex;
                }
                else Thread.Sleep(100);

            }
        } while (!done);
    }
}

/* Now we can create the context and use that to create the DB. Note that
 * a custom constructor's been added to the context exposing the base
 * constructor that can take a connection string- changing the connection
 * string after the default constructor reads it from App.config isn't 
 * sufficient.
 */
EventsListDBEntities ctx = new EventsListDBEntities(connectionString);
ctx.Database.Create();
int numRecords = ctx.EventLists.Count(); //See if it really worked.