Entity Framework Code-pierwsze problemy (SimpleMembership USERPROFILE table)
Jeśli użyłeś ASP.NET MVC 4 zauważysz, że domyślnym dla aplikacji internetowej jest korzystanie z dostawcy SimpleMembership, to wszystko jest dobrze i dobrze i działa dobrze.
Problem pochodzi z domyślnym generowaniem bazy danych, mają POCO dla UserProfile
zdefiniowane w następujący sposób:
[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 w następujący sposób:
using (var context = new UsersContext())
{
if (!context.Database.Exists())
{
// Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
To działa dobrze, baza danych jest generowana dobrze i działa bez problemu. Jeśli jednak mam tak zmienić POCO i usunąć baza 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 dobrze pod względem kodu (gadające Logowanie/Rejestracja), ale oczywiście żadne z moich innych danych użytkownika nie jest przechowywane.
UserProfile
. 4 answers
1 - Musisz włączyć migracje, najlepiej z EntityFramework 5. Użyj Enable-Migrations
w menedżerze pakietów NuGet.
2-Przenieś swoje
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "EmailAddress", autoCreateTables: true);
Do metody Seed w YourMvcApp / Migrations / 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 zrobieniu tego wywołasz WebSecurity.InitializeDatabaseConnection rejestruje tylko SimpleMembershipProvider z już utworzoną tabelą UserProfile, a także informuje SimpleMembershipProvider, która kolumna jest identyfikatorem użytkownika i nazwą użytkownika. Pokazuję również przykład, w jaki sposób można dodać użytkowników, role i powiązać te dwa w swojej metodzie zalążkowej z niestandardowymi właściwościami/polami UserProfile, np.
3-Teraz, gdy uruchomisz update-database z konsoli Menedżera pakietów, EF5 udostępni Twoją tabelę ze wszystkimi własnymi właściwościami
Aby uzyskać dodatkowe odniesienia, zapoznaj się z tym artykułem z kodem źródłowym: http://blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties/
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-23 20:51:56
Wygląda na to, że w końcu to zrozumiałem i to mogło być tylko jedno wielkie nieporozumienie.
Jak się okazało, spodziewałem się ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
zrobić to, czego po prostu nie ma, czyli stworzyć wszystkie tabele w bazie danych, które nie istnieją, lub po prostu zaktualizować je, jeśli tak się stanie i są inne.
To, co się naprawdę dzieje, to to, że dosłownie uruchamia CREATE DATABASE
oświadczenie, które dla mnie jest najbardziej bezużyteczną rzeczą w historii. Jeśli nie pracujesz w naprawdę dziwnym środowisku, zawsze będziesz mieć bazę danych na wyłączonym i tak będzie zawsze istnieć (a następnie tworzenie tabeli nigdy nie nastąpi!), Wolałbym i tak nie dawać realnym użytkownikom dostępu do tworzenia bazy danych.
W każdym razie, rozwiązałem mój konkretny problem, chcąc UserProfile
(i powiązanych tabel) do tworzenia bazy danych za pomocą inicjalizatora DropCreateDatabaseIfModelChanges
i wymuszając inicjalizację 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 dość bezużyteczny w praktyce, ponieważ będzie dosłownie upuść bazę danych i odtworz ją od zera, jeśli model ulegnie zmianie. Dla mnie to sprawia, że cały kod-pierwsza praktyka prawie bezużyteczna w jego domyślnej formie i prawdopodobnie skończę z powrotem do generacji z-DB edmx.
"tajemnicą" za UserProfile
wciąż tworzoną tabelą jest to, że WebSecurity.InitializeDatabaseConnection
zainicjalizuje tabelę, jeśli nie istnieje w oparciu o pola, które do niej przekazujesz, dlatego EmailAddress
została utworzona zamiast UserName
, ponieważ zmieniłem ją w tym.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-23 22:47:51
Miałem ten sam problem. Dodałem kod, aby migracje miały miejsce tuż przed "CreateDatabase" w SimpleMembershipInitializer.
To naprawiło problem dla mnie, z tym wyjątkiem, że wierzę, że teraz moje migracje będą stosowane na platformie Azure bez względu na ustawienie w profilu publikowania.
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
{....
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-21 23:39:29
Jeśli nie masz planów wprowadzania zmian po uruchomieniu systemu i dzieje się to tylko w fazie rozwoju i nie chcesz włączyć migracji. Spróbuj obciąć tabelę _ _ MigrationHistory.
truncate table __MigrationHistory
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-04 06:49:41