2013-04-12 76 views
4

我试图在我的网站上使用基于实体框架代码的迁移。我目前有一个包含多个项目的解决方案。有一个Web API项目,我想要初始化数据库和另一个名为DataLayer项目的项目。我已经在DataLayer项目中启用了迁移,并创建了一个初始迁移,我希望它将用于创建数据库(如果它不存在)。实体框架MigrateDatabaseToLatestVersion给出错误

下面是当我启用迁移

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(); 

如果我运行一个数据库,这是否存在,我得到以下错误

Directory查找对于文件“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项目调用此项目有关?

+0

看起来像是一个连接字符串运行在我的Global.asax这段代码,和路径你指着你对SQL设置服务器。我会确保连接字符串安装正确,并且可以访问并写入所需的所有内容。 –

+0

我想知道,但如果我可以只是将MigrateDatabaseToLatestVersion的一行切换出来并用DropCreateDatabaseAlways替换它,并且它完美地工作,那么我会认为连接字符串不会是问题,因为两者都会使用它 –

+0

好的我有搞清楚了,它确实与连接字符串有关,但我想我对另一个策略的工作方式仍然感到困惑。我们使用UnitOfWork设计模式,当您构建UnitOfWork时,它会创建一个上下文并将连接字符串传递给它,所以我们在Web配置文件中不需要它。在使用MigrateDatabaseToLatestVersion策略时,必须将连接字符串放入Web.Config才能使其工作,但DropCrerateDatabaseAlways的工作没有问题。在初始化数据库之前,我正在使用UnitOfWork创建上下文。为什么?? –

回答

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; 
    } 
} 

一旦我做到了我coudl没有问题

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