20

我試圖創建一個新的數據庫使用實體框架的代碼第一個概念。但是,運行代碼時,不會創建數據庫(使用DropCreateDatabaseIfModelChanges設置),儘管代碼運行良好。當我嘗試從數據庫中獲取某些內容時,發現以下異常。實體框架5代碼優先不創建數據庫

enter image description here

我的項目是使用一個單獨的DataAccess層與通用服務和資源庫建設安裝。所以我所有的實體,存儲庫和數據庫上下文都在解決方案中的一個單獨項目中。我的global.asax文件包含以下代碼段。

Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>()); 

這應該初始化一個新的數據庫,如果它不存在,對嗎?

我的數據庫上下文類看起來像這樣;

namespace Website.DAL.Model 
{ 
    public class MyContext : DbContext 
    { 
     public IDbSet<Project> Projects { get; set; } 
     public IDbSet<Portfolio> Portfolios { get; set; } 

     /// <summary> 
     /// The constructor, we provide the connectionstring to be used to it's base class. 
     /// </summary> 
     public MyContext() 
      : base("MyConnectionString") 
     { 
     } 

     static MyContext() 
     { 
      try 
      { 
       Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>()); 
      } 
      catch (Exception) 
      { 
       throw; 
      } 
     } 

     /// <summary> 
     /// This method prevents the plurarization of table names 
     /// </summary> 
     /// <param name="modelBuilder"></param> 
     protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      base.OnModelCreating(modelBuilder); 
      modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>(); 
     } 
    } 
} 

我在互聯網上的幾個教程和文章後創建了這個類。這對我來說都是新的,但據我所知,一切似乎都是正確的。所以現在我正在使用的兩個實體。他們被稱爲'項目'和'投資組合'。他們看起來像這樣;

public class Portfolio 
    { 
     [Key] 
     public Guid Id { get; set; } 
     public String Name { get; set; } 
     public DateTime StartDate { get; set; } 
     public DateTime? EndDate { get; set; } 
     public bool IsPublished { get; set; } 

     public virtual ICollection<Project> Projects { get; set; } 
    } 

而且

public class Project 
    { 
     [Key] 
     public Guid Id { get; set; } 
     public DateTime StartDate { get; set; } 
     public DateTime? EndDate { get; set; } 
     public bool IsPublished { get; set; } 
     public String Title { get; set; } 
    } 

我使用一個外部服務器上運行的數據庫,它帶着我使用了託管服務提供商。我已經啓動了一個SQL Server數據庫,並且該數據庫的連接字符串位於網站項目的web.config中。我已經嘗試刪除數據庫,並讓代碼重新創建它,但不幸的是沒有工作。我在這裏錯過了很明顯的東西嗎或者它可能是一個簡單的東西,作爲創建數據庫的服務器的訪問權限?

注:當我運行Database-Update -Script命令生成SQL代碼,它似乎是正確的SQL語句來創建創建的所有表。

UPDATE 1: 好的,多虧了一些評論,我來得更進一步。我已經爲我的實體添加了兩個屬性來強制進行一些更改,並且我還創建了一個像這樣的自定義初始化程序;

public class ForceDeleteInitializer : IDatabaseInitializer<MyContext> 
    { 
     private readonly IDatabaseInitializer<MyContext> _initializer = new DropCreateDatabaseIfModelChanges<MyContext>(); 

     public ForceDeleteInitializer() 
     { 
      //_initializer = new ForceDeleteInitializer(); 
     } 

     public void InitializeDatabase(MyContext context) 
     { 
      //This command is added to prevent open connections. See http://stackoverflow.com/questions/5288996/database-in-use-error-with-entity-framework-4-code-first 
      context.Database.ExecuteSqlCommand("ALTER DATABASE borloOntwikkel SET SINGLE_USER WITH ROLLBACK IMMEDIATE"); 
      _initializer.InitializeDatabase(context); 
     } 
    } 

我也從我的上下文的構造函數中刪除了初始化器,所以這意味着我已經刪除了這行代碼;

Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>()); 

之後,我已經將這三行添加到我的全球。asax文件;

Database.SetInitializer(new ForceDeleteInitializer()); 
MyContext c = new MyContext(); 
c.Database.Initialize(true); 

當調試我現在得到這個異常; enter image description here

這給了我以下信息:

  • 的InnerException說:提供程序未返回在InnerException一個 ProviderManifestToken
  • 的InnerException說:「對於這種操作方式的連接masterdatabase是必需的。連接不能爲 因爲原來的連接是 已打開並且已從連接中刪除引用而使寬度爲'主'數據庫。請提供非開放連接」

這些動作後無法訪問數據庫,所以最有可能被刪除..

什麼都不可能瞭解這一點呢?這很可能是我無法訪問master數據庫,因爲我的主機提供商不會給我正確的訪問權限。

+0

代碼和配置看起來確定,你可能停留在託管情況。 EF想要創建一個帶有特殊幫助表的Db(1或2個哈希)。也許你可以從本地Db編寫腳本並將其移至託管的Db? –

+0

運行代碼的用戶帳戶是否具有刪除和創建數據庫的必要權限? – jlew

+0

@亨克,我剛剛嘗試運行生成的SQL腳本。它用一條記錄爲我創建了一個__MigrationHistory表。我還通過添加'this.Database.Initialize(true)'行來修改我的上下文的構造函數。這並沒有給我一個錯誤,但也沒有創建任何表。然後我從MigrationHistory表中刪除記錄,並再次發生同樣的錯誤。所以我會嘗試在本地數據庫上運行它,看看會發生什麼。 – Rob

回答

12

由於沒有其他的解決方案來過我決定改變我的做法。

我自己首先創建了數據庫,並確保正確的SQL用戶已配置,並且有權訪問。

然後我從Global.asax文件中刪除了初始值設定項和代碼。之後,我在包管理器控制檯中運行了以下命令(因爲分層設計我不得不在控制檯中選擇正確的項目);

Enable-Migrations 

在遷移後能在那裏和我做了一些最後一分鐘改變我的實體,我跑下面的命令來腳手架的新移民;

Add-Migration AddSortOrder 

我的遷移創建後,我在控制檯運行下面的命令,瞧,數據庫是用我的實體更新;

Update-Database -Verbose 

爲了能夠運行遷移我已經覆蓋了種子法在我Configuraton.cs類,這是使遷移時創建,當種子數據庫。這種方法的最終代碼就是這樣的;

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

      //Add menu items and pages 
      if (!context.Menu.Any() && !context.Page.Any()) 
      { 
       context.Menu.AddOrUpdate(new Menu() 
              { 
               Id = Guid.NewGuid(), 
               Name = "MainMenu", 
               Description = "Some menu", 
               IsDeleted = false, 
               IsPublished = true, 
               PublishStart = DateTime.Now, 
               LastModified = DateTime.Now, 
               PublishEnd = null, 
               MenuItems = new List<MenuItem>() 
                   { 
                    new MenuItem() 
                     { 
                      Id = Guid.NewGuid(), 
                      IsDeleted = false, 
                      IsPublished = true, 
                      PublishStart = DateTime.Now, 
                      LastModified = DateTime.Now, 
                      PublishEnd = null, 
                      Name = "Some menuitem", 
                      Page = new Page() 
                         { 
                          Id = Guid.NewGuid(), 
                          ActionName = "Some Action", 
                          ControllerName = "SomeController", 
                          IsPublished = true, 
                          IsDeleted = false, 
                          PublishStart = DateTime.Now, 
                          LastModified = DateTime.Now, 
                          PublishEnd = null, 
                          Title = "Some Page" 
                         } 
                     }, 
                    new MenuItem() 
                     { 
                      Id = Guid.NewGuid(), 
                      IsDeleted = false, 
                      IsPublished = true, 
                      PublishStart = DateTime.Now, 
                      LastModified = DateTime.Now, 
                      PublishEnd = null, 
                      Name = "Some MenuItem", 
                      Page = new Page() 
                         { 
                          Id = Guid.NewGuid(), 
                          ActionName = "Some Action", 
                          ControllerName = "SomeController", 
                          IsPublished = true, 
                          IsDeleted = false, 
                          PublishStart = DateTime.Now, 
                          LastModified = DateTime.Now, 
                          PublishEnd = null, 
                          Title = "Some Page" 
                         } 
                     } 
                   } 
              }); 
      } 

      if (!context.ComponentType.Any()) 
      { 
       context.ComponentType.AddOrUpdate(new ComponentType() 
       { 
        Id = Guid.NewGuid(), 
        IsDeleted = false, 
        IsPublished = true, 
        LastModified = DateTime.Now, 
        Name = "MyComponent", 
        PublishEnd = null, 
        PublishStart = DateTime.Now 
       }); 
      } 


      try 
      { 
       // Your code... 
       // Could also be before try if you know the exception occurs in SaveChanges 

       context.SaveChanges(); 
      } 
      catch (DbEntityValidationException e) 
      { 
       //foreach (var eve in e.EntityValidationErrors) 
       //{ 
       // Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:", 
       //  eve.Entry.Entity.GetType().Name, eve.Entry.State); 
       // foreach (var ve in eve.ValidationErrors) 
       // { 
       //  Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"", 
       //   ve.PropertyName, ve.ErrorMessage); 
       // } 
       //} 
       //throw; 

       var outputLines = new List<string>(); 
       foreach (var eve in e.EntityValidationErrors) 
       { 
        outputLines.Add(string.Format(
         "{0}: Entity of type \"{1}\" in state \"{2}\" has the following validation errors:", 
         DateTime.Now, eve.Entry.Entity.GetType().Name, eve.Entry.State)); 
        foreach (var ve in eve.ValidationErrors) 
        { 
         outputLines.Add(string.Format(
          "- Property: \"{0}\", Error: \"{1}\"", 
          ve.PropertyName, ve.ErrorMessage)); 
        } 
       } 
       System.IO.File.AppendAllLines(@"c:\temp\errors.txt", outputLines); 
       throw; 
      } 
     } 

目前的缺點是我必須在包管理器控制檯中手動遷移(僅)2個命令。但是同時,這種情況不會動態發生也是很好的,因爲這樣可以防止對我的數據庫進行可能不需要的更改。進一步的一切都很完美。

1

+1的詳細問題。

檢查您的連接字符串是在正確的數據庫指向,並添加授權屬性這樣來訪問數據庫:

<add name="PatientContext" providerName="System.Data.SqlClient" connectionString="Server=SQLSERVER2; Database=Patients; uid=PatientUser; password=123456; Integrated Security=False;" /> 
0

befor intialize它運行下面的代碼來創建數據庫:

context.Database.CreateIfNotExists();

相關問題