4

我正在尝试在我的网站上使用基于实体框架代码的迁移。我目前有一个包含多个项目的解决方案。有一个我想初始化数据库的 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 可以看到它并在它的数据库初始化程序中使用它。下面是我用来尝试初始化数据库的 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(系统找不到指定的文件。)。

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

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

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

数据库将在需要的地方正确创建。

我不知道是什么原因造成的。可能是我需要在配置类中添加其他内容,还是与我的所有迁移信息都在 DataLayer 项目中但我从 WebAPI 项目中调用它的事实有关?

4

1 回答 1

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);
}
于 2013-04-16T20:19:51.790 回答