2012-09-19 49 views
28

如果您使用過ASP.NET MVC 4,您會注意到Internet應用程序的默認設置是使用SimpleMembership提供程序,這一切都很好,精細。實體框架代碼優先問題(SimpleMembership UserProfile表格)

問題自帶的默認數據庫的一代,他們有一個POCO的UserProfile像這樣定義的:

[Table("UserProfile")] 
public class UserProfile 
{ 
    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int UserId { get; set; } 
    public string UserName { get; set; } 
} 

..然後將這樣產生的:

using (var context = new UsersContext()) 
{ 
    if (!context.Database.Exists()) 
    { 
     // Create the SimpleMembership database without Entity Framework migration schema 
     ((IObjectContextAdapter)context).ObjectContext.CreateDatabase(); 
    } 
} 

這工作得很好,數據庫生成得很好,工作沒有問題。但是,如果我改變POCO這樣並刪除數據庫:

[Table("UserProfile")] 
public class UserProfile 
{ 
    [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int UserId { get; set; } 
    public string EmailAddress { get; set; } 

    public string FirstName { get; set; } 
    public string Surname { get; set; } 

    public string Country { get; set; } 

    public string CompanyName { get; set; } 
} 

只有第2列生成,UserIdEmailAddress。它工作正常代碼明智(說話登錄/註冊),但顯然沒有我的其他用戶數據存儲。

我在這裏錯過了什麼嗎?當然,它應該基於整個對象生成數據庫。

+0

看起來很奇怪。這是可重複的嗎?即清理並重建所有內容,重新檢查結果。你在看正確的Db嗎? –

+1

@HenkHolterman不幸的是,在過去的兩天裏,我一直在爲自己瘋狂,我甚至試着用自己的名字來歸屬每一列,而他們根本就不在那裏。更糟糕的是'UserId'和'EmailAddress'(或者我重命名的)*都很好。 –

+0

@HenkHolterman還應該值得注意的是,我試圖在一個全新的項目上更改這張表,就像一個測試一樣,它也有同樣的問題。我還沒有嘗試過使用實體框架獨立生成數據庫,也許我會做下一步,但寧願保持儘可能與默認的ASP.NET MVC4結構保持一致.. –

回答

5

看來我終於可以得到這個了,它可能只是一個巨大的誤解。

事實證明,我期待((IObjectContextAdapter)context).ObjectContext.CreateDatabase();做它根本不做的事情,它是創建數據庫中所有不存在的表,或者只是更新它們,如果他們這樣做,他們是不同的。

實際上發生的是它實際上運行一個CREATE DATABASE聲明,對我而言這是最無用的事情。除非你在一個非常奇怪的環境中工作,否則你總是會有一個關閉的數據庫,所以它一直存在(並且隨後表的創建永遠不會發生!),我寧願不讓真實世界的用戶訪問無論如何創建一個數據庫。

無論如何,我想解決UserProfile(及相關表格)使用DropCreateDatabaseIfModelChanges初始化,並迫使象下面這樣初始化創建數據庫的我的具體問題:

public SimpleMembershipInitializer() 
{ 
#if DEBUG 
    Database.SetInitializer<DataContext>(new DropCreateDatabaseIfModelChanges<DataContext>()); 
#else 
    Database.SetInitializer<DataContext>(null); 
#endif 

    try 
    { 
     using (var context = new DataContext()) 
     { 
      if (!context.Database.Exists()) 
      { 
       ((IObjectContextAdapter)context).ObjectContext.CreateDatabase(); 
      } 
      context.Database.Initialize(true); 
     } 

     WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "EmailAddress", autoCreateTables: true); 
    } 
    catch (Exception ex) 
    { 
     throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex); 
    } 
} 

..這個作品,是完美對於開發而言,但在實踐中毫無用處,因爲如果模型更改,它將逐字刪除數據庫並從頭開始重新創建它。對我來說,這使得整個代碼優先的做法在默認形式中幾乎沒有用處,我可能最終會恢復到from-DB edmx代。

「神祕」仍正在創建的UserProfile桌子後面是WebSecurity.InitializeDatabaseConnection將初始化表,如果它不存在根據你進入它的領域,這就是爲什麼EmailAddress創建的UserName代替,因爲我在這改變了它。

+0

您確實知道這是EF Migrations的用途,對嗎?這是無用的,因爲這不是你從一個版本遷移到另一個版本的方式。 EF有一個特定的用例。另外,你的問題說你每次都刪除了數據庫,看起來你實際上並沒有刪除它,但是期待EF爲你改變模式。如果你真的給我們提供了正確的信息,我們可以給你一個真正的迴應。這就是爲什麼你有很多頭撓,因爲你的問題說你做了你沒有做的事。 –

+0

我不確定爲什麼你會認爲所謂'CreateDatabase()'實際上並沒有真正創建數據庫。這不是無用的,因爲它旨在創建數據庫,當它不存在時,這是您告訴我們的情況。 –

+0

@MystereMan是的我意識到這一點,這正是我的帖子總結這是;誤會!它部分源於其他SO帖子,涉及類似的問題,其中有人告訴'改變班級自動更新表格'。至於「刪除數據庫」,我給出的信息當然是不正確的,因爲我實際上正在刪除數據庫*內容*。我的困惑來自於我的'UserProfile'表仍然在創建(儘管不正確),但現在我意識到它是'InitializeDatabaseConnection'。這是一個非常**很長的幾個星期:) –

47

1 - 您需要啓用遷移,優先使用EntityFramework 5.在NuGet包管理器中使用Enable-Migrations

2 - 將您

WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "EmailAddress", autoCreateTables: true); 

你的後裔方法在你的YourMvcApp /遷移/配置。CS類

protected override void Seed(UsersContext context) 
    { 
     WebSecurity.InitializeDatabaseConnection(
      "DefaultConnection", 
      "UserProfile", 
      "UserId", 
      "UserName", autoCreateTables: true); 

     if (!Roles.RoleExists("Administrator")) 
      Roles.CreateRole("Administrator"); 

     if (!WebSecurity.UserExists("lelong37")) 
      WebSecurity.CreateUserAndAccount(
       "lelong37", 
       "password", 
       new {Mobile = "+19725000000", IsSmsVerified = false}); 

     if (!Roles.GetRolesForUser("lelong37").Contains("Administrator")) 
      Roles.AddUsersToRoles(new[] {"lelong37"}, new[] {"Administrator"}); 
    } 

現在EF5將負責創建用戶配置表,這樣做後,你將調用WebSecurity.InitializeDatabaseConnection只註冊SimpleMembershipProvider與已經建立的用戶配置表,也tellling SimpleMembershipProvider這列是用戶ID的和用戶名。我還展示瞭如何添加用戶,角色並將您的Seed方法中的兩者與自定義UserProfile屬性/字段關聯的示例,例如用戶的手機(號碼)。

3 - 現在當你從包管理器控制檯運行更新的數據庫,EF5將提供與您的所有自定義屬性

有關其他參考資料,請參閱這篇文章源代碼的表: http://blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties/

+0

不是我所問的100%,但對於其他可能有同樣問題的人來說,這絕對是100%的幫助!感謝rudi_visser享受賞金 –

+0

。 – LeLong37

+0

僅供參考,更新開發數據庫時,將WebSecurity.InitializeDatabaseConnection移至種子方法崩潰(「角色管理器功能尚未啓用」錯誤)。 – rufo

2

我遇到了同樣的問題。我添加了代碼,以便在SimpleMembershipInitializer中的「CreateDatabase」之前進行遷移。

這解決了我的問題,除了我相信現在我的遷移將在Azure中應用,無論發佈配置文件中的設置如何。

private class SimpleMembershipInitializer 
    { 
     public SimpleMembershipInitializer() 
     { 
      Database.SetInitializer<WomContext>(null); 

      // forcing the application of the migrations so the users table is modified before 
      // the code below tries to create it. 
      var migrations = new MigrateDatabaseToLatestVersion<WomContext, Wom.Migrations.Configuration>(); 
      var context = new WomContext(); 
      migrations.InitializeDatabase(context); 

      try 
      {.... 
0

如果你沒有計劃進行一次更改系統是活的,這隻有在發生發展,而不是熱衷於實現遷移。嘗試截斷表__MigrationHistory。

truncate table __MigrationHistory