2012-09-19 14 views
28

Jeśli korzystałeś z ASP.NET MVC 4, zauważysz, że domyślną aplikacją Internetową jest użycie dostawcy SimpleMembership, wszystko jest w porządku i działa w porządku.Entity Framework Code-First Issues (SimpleMembership UserProfile table)

Problem pochodzi z pokolenia domyślnej bazy danych, mają POCO dla UserProfile zdefiniowane tak:

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

.. który następnie jest generowany tak:

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

Działa to dobrze, baza danych jest generowana dobrze i działa bez problemu. Jednak jeśli mam zmienić poco takiego i usuwać bazy danych:

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

generowane są tylko pierwsze 2 kolumny, UserId i EmailAddress. Działa tylko w porządku kodowym (logowanie/rejestracja), ale oczywiście żaden z moich innych danych użytkownika nie jest przechowywany.

Czy tu czegoś brakuje? Z pewnością powinien wygenerować bazę danych opartą na całym obiekcie UserProfile.

+0

Wygląda dziwnie. Czy to jest powtarzalne? To znaczy. Oczyść i odbuduj wszystko, dwukrotnie sprawdź wyniki. Patrzysz w prawo Db? –

+1

@HenkHolterman Niestety tak, doprowadzałem się do szaleństwa przez ostatnie 2 dni, próbowałem nawet przypisać każdą kolumnę swoim własnym imieniem i po prostu ich tam nie ma. Co gorsza jest to, że 'UserId' i' EmailAddress' (lub jakkolwiek to zmieniam) * są * w porządku. –

+0

@HenkHolterman Warto również zauważyć, że próbowałem zmienić tę tabelę na zupełnie nowym projekcie, tak jak test i ma ten sam problem. To, czego nie próbowałem, to samodzielne generowanie bazy danych za pomocą Entity Framework, może zrobię to później, ale wolałbym pozostać jak najbardziej dostosowany do domyślnej struktury ASP.NET MVC4 na teraz. –

Odpowiedz

5

Wygląda na to, że w końcu udało mi się to osiągnąć i mogło to być jedno wielkie nieporozumienie.

Okazuje się, że oczekiwałem, że ((IObjectContextAdapter)context).ObjectContext.CreateDatabase(); zrobi to, czego po prostu nie zrobi, czyli utworzy wszystkie tabele w bazie danych, które nie istnieją, lub po prostu je zaktualizuje, jeśli tak się stanie, a one są różne .

To, co się dzieje, to fakt, że dosłownie prowadzi on do oświadczenia CREATE DATABASE, które jest dla mnie najbardziej bezużyteczną rzeczą. Jeśli nie pracujesz w naprawdę dziwnym środowisku, zawsze będziesz mieć bazę danych off-off i tak będzie zawsze istnieć (a potem tworzenie tabeli nigdy by się nie wydarzyło!), Wolałbym nie dawać dostępu realnym użytkownikom mimo to utworzyć bazę danych.

Zresztą rozwiązać mój problem z konkretną chcąc UserProfile (i tabele pokrewne), aby utworzyć bazę danych za pomocą DropCreateDatabaseIfModelChanges inicjator i zmuszając inicjalizacji jak poniżej:

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

.. To działa i jest idealny do rozwoju, ale jest praktycznie bezużyteczne w praktyce, ponieważ dosłownie upuści bazę danych i odtworzy ją od nowa, jeśli model ulegnie zmianie. Dla mnie to sprawia, że ​​cała pierwsza praktyka kodu jest prawie bezużyteczna w domyślnej formie i prawdopodobnie powrócę do generowania edmx z DB.

„Tajemnica” za stołem UserProfile nadal tworzony jest WebSecurity.InitializeDatabaseConnection będzie zainicjować tabeli, jeśli nie istnieje na podstawie pól, które przechodzą do niego, dlatego też EmailAddress powstał zamiast UserName, bo zmieniło to w tym.

+0

Zdajesz sobie sprawę, że do tego właśnie służy EF Migrations, prawda? Jest bezużyteczny, ponieważ nie jest to sposób migracji z jednej wersji do drugiej. EF ma do tego specjalne zastosowanie. Ponadto, twoje pytanie mówiło, że usuwałeś bazę danych za każdym razem, kiedy wydaje się, że faktycznie jej nie usuwałeś, ale oczekujesz, że EF zmieni w magiczny sposób Twój schemat. Gdybyś podał nam prawidłowe informacje, moglibyśmy dać ci prawdziwą odpowiedź. To dlatego masz dużo drapania głowy, ponieważ twoje pytanie mówiło, że robisz rzeczy, których nie robiłeś. –

+0

Nie jestem pewien, dlaczego uważasz, że coś o nazwie "CreateDatabase()" faktycznie nie dosłownie utworzyć bazę danych. To nie jest bezużyteczne, ponieważ ma na celu stworzenie bazy danych, gdy jej nie ma, co jest sytuacją, o której nam mówisz. –

+0

@MystereMan Tak, jestem tego świadomy i to jest dokładnie to, co mój post podsumował jako; nieporozumienie! Częściowo wynikało to z innych wpisów dotyczących SO związanych z podobnymi problemami, w których powiedziano, że "zmiana klasy automatycznie aktualizuje tabele". Informacje, które podałem w odniesieniu do "usuwania bazy danych" były oczywiście nieprawidłowe, ponieważ faktycznie kasowałem bazę danych * zawartość *.Moje zamieszanie wynikało z faktu, że moja tabela 'UserProfile' wciąż była tworzona (chociaż niepoprawnie), ale teraz zdaję sobie sprawę, że jest to' InitializeDatabaseConnection'. To było ** bardzo ** długie kilka tygodni :) –

47

1 - Musisz włączyć migrację, najlepiej w EntityFramework 5. Użyj Enable-Migrations w menedżerze pakietów NuGet.

2 - Najedź

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

nasieniu twemu metodę w swojej YourMvcApp/Migracje/configuration.klasa 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"}); 
    } 

Teraz EF5 będzie odpowiedzialny za tworzenie tabeli USERPROFILE, po wykonaniu tych czynności można nazwać WebSecurity.InitializeDatabaseConnection się zarejestrować tylko SimpleMembershipProvider z już utworzonej tabeli UserProfile również tellling SimpleMembershipProvider która kolumna jest UserId i nazwa użytkownika. Pokazuję również przykład, w jaki sposób można dodawać użytkowników, role i powiązanie tych dwóch w swojej metodzie seed z niestandardowymi właściwościami/polami UserProfile, np. telefon komórkowy użytkownika (numer).

3 - Teraz po uruchomieniu update-bazy danych z pakietu konsoli Menedżer EF5 będzie przepis tabela ze wszystkimi swoimi właściwościami niestandardowymi

uzyskać dodatkowe referencje zapoznaj się z tym artykułem z kodu źródłowego: http://blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties/

+0

Nie 100% o co prosiłem, ale z pewnością jest w 100% pomocne dla innych, którzy mogą mieć ten sam problem! Ciesz się nagrodą –

+0

dzięki, rudi_visser. – LeLong37

+0

FYI, Przeniesienie WebSecurity.InitializeDatabaseConnection do metody seed powoduje awarię podczas aktualizacji rozwojowej bazy danych (błąd "Funkcja Role Manager nie został włączony"). – rufo

2

Miałem ten sam problem. Dodałem kod, aby migracje miały miejsce tuż przed "CreateDatabase" w SimpleMembershipInitializer.

tej stałej problem dla mnie, poza tym, że wierzę, że teraz moje migracje będą stosowane w Azure niezależnie ustawienie w profilu wydawniczego.

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

Jeśli nie masz planów na wprowadzenie zmian, gdy system jest na żywo i to dzieje się tylko w rozwoju i nie chętni, aby umożliwić migrację. Spróbuj obcinać tabelę __MigrationHistory.

truncate table __MigrationHistory