2013-04-12 75 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); 
}