实体框架MigrateDatabaseToLatestVersion给出错误

时间:2013-04-12 20:20:55

标签: entity-framework entity-framework-5

我正在尝试使用基于Entity Framework代码的迁移到我的网站。我目前有一个包含多个项目的解决方案。我想要初始化数据库的Web API项目和另一个名为DataLayer项目的项目。我已在DataLayer项目中启用了迁移并创建了一个初始迁移,我希望它将用于创建数据库(如果它不存在)。

这是我启用迁移时获得的配置

public sealed class Configuration : DbMigrationsConfiguration<Harris.ResidentPortal.DataLayer.ResidentPortalContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(Harris.ResidentPortal.DataLayer.ResidentPortalContext context)
    {
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
        //  to avoid creating duplicate seed data. E.g.
        //
        //    context.People.AddOrUpdate(
        //      p => p.FullName,
        //      new Person { FullName = "Andrew Peters" },
        //      new Person { FullName = "Brice Lambson" },
        //      new Person { FullName = "Rowan Miller" }
        //    );
        //
    }
}

我在创建它之后对此进行的唯一更改是将其从内部更改为公共,以便WebAPI可以看到它并在其databaseinitializer中使用它。下面是我用来尝试初始化数据库的Application_Start代码中的代码

Database.SetInitializer(new MigrateDatabaseToLatestVersion<ResidentPortalContext, Configuration>());
new ResidentPortalUnitOfWork().Context.Users.ToList();

如果我运行它,无论数据库是否存在,我都会收到以下错误

  

文件“C:\ Users \ Dave \ Documents \ Visual Studio 2012 \ Projects \ ResidentPortal \ Harris.ResidentPortal.WebApi \ App_Data \ Harris.ResidentPortal.DataLayer.ResidentPortalContext.mdf”的目录查找失败,出现操作系统错误2(系统找不到指定的文件。)。

     

CREATE DATABASE失败。无法创建列出的某些文件名。检查相关错误。

看起来它正在寻找数据库完全错误的地方。它似乎与我正在初始化数据库的这种特殊方式有关,因为如果我将代码更改为以下内容。

Database.SetInitializer(new DropCreateDatabaseAlways<ResidentPortalContext>());
new ResidentPortalUnitOfWork().Context.Users.ToList();

数据库将在需要的位置正确创建。

我对造成它的原因感到茫然。可能是我需要在配置类中添加其他内容,还是与我的所有迁移信息都在DataLayer项目中但我从WebAPI项目中调用它这一事实有关?

1 个答案:

答案 0 :(得分:8)

我已经想出了如何为此进程创建动态连接字符串。您需要先将此行添加到Web或App.Config上的EntityFramework条目中,而不是默认情况下放在那里的行。

<defaultConnectionFactory type="<Namespace>.<ConnectionStringFacotry>, <Assembly>"/>  

这告诉程序你有自己的工厂将返回DbConnection。下面是我用来制作自己工厂的代码。部分原因在于,一群程序员使用相同的代码集,但有些人使用SQL Express,而其他人使用完整的SQL Server。但是这会给你一个例子来说明你需要的东西。

public sealed class ResidentPortalConnectionStringFactory: IDbConnectionFactory 
{
    public DbConnection CreateConnection(string nameOrConnectionString)
    {
        SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["PortalDatabase"].ConnectionString);

        //save off the original catalog
        string originalCatalog = builder.InitialCatalog;

        //we're going to connect to the master db in case the database doesn't exist yet
        builder.InitialCatalog = "master";
        string masterConnectionString = builder.ToString();

        //attempt to connect to the master db on the source specified in the config file
        using (SqlConnection conn = new SqlConnection(masterConnectionString))
        {
            try
            {
                conn.Open();
            }
            catch
            {
                //if we can't connect, then append on \SQLEXPRESS to the data source
                builder.DataSource = builder.DataSource + "\\SQLEXPRESS";
            }
            finally
            {
                conn.Close();
            }
        }

        //set the connection string back to the original database instead of the master db
        builder.InitialCatalog = originalCatalog;

        DbConnection temp = SqlClientFactory.Instance.CreateConnection();
        temp.ConnectionString = builder.ToString();

        return temp;
    }
}

一旦我这样做,我就可以在我的Global.asax中运行此代码而没有任何问题

Database.SetInitializer(new MigrateDatabaseToLatestVersion<ResidentPortalContext, Configuration>());
using (ResidentPortalUnitOfWork temp = new ResidentPortalUnitOfWork())
{
    temp.Context.Database.Initialize(true);
}