2012-09-19 11 views
28

Si usó ASP.NET MVC 4 notará que el valor predeterminado para una aplicación de Internet es usar el proveedor SimpleMembership, todo está bien y funciona multa.Primer código de Entity Framework-First Issues (tabla de perfil de usuario de SimpleMembership)

El problema viene con la generación de bases de datos por defecto, tienen un POCO de UserProfile define así:

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

.. que luego se genera de esta manera:

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

Esto funciona bien, la base de datos se genera muy bien y funciona sin problemas. Sin embargo, si he de cambiar la POCO como este y eliminar la base de datos:

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

Sólo se generan las primeras 2 columnas, UserId y EmailAddress. Funciona muy bien en código (hablando de inicio de sesión/registro), pero obviamente ninguno de mis otros datos de usuario se almacena.

¿Falta algo aquí? Seguramente debería generar la base de datos basada en el objeto completo UserProfile.

+0

Looks odd. Es esto repetible? Es decir. Limpia y reconstruye todo, comprueba dos veces los resultados. ¿Estás mirando a la derecha Db? –

+1

@HenkHolterman Desafortunadamente sí, he estado volviendo loco por los últimos 2 días con esto, incluso intenté atribuir cada columna con su propio nombre y simplemente no están allí. Lo que lo empeora es que 'UserId' y' EmailAddress' (o lo que sea que les cambie el nombre) * están * allí bien. –

+0

@HenkHolterman También vale la pena señalar que he intentado cambiar esta tabla en un proyecto completamente nuevo solo como prueba y tiene el mismo problema. Lo que no he intentado es usar Entity Framework de forma independiente para generar la base de datos, tal vez lo haga a continuación, pero prefiero mantenerme alineado con la estructura predeterminada de ASP.NET MVC4 como sea posible por ahora ... –

Respuesta

5

Parece que finalmente pude tener esto, y puede haber sido un gran malentendido.

Como resultado, esperaba ((IObjectContextAdapter)context).ObjectContext.CreateDatabase(); hacer lo que simplemente no hace, que es crear todas las tablas en la base de datos que no existen, o simplemente actualizarlas si lo hacen y son diferentes .

Lo que realmente ocurre es que literalmente ejecuta una declaración CREATE DATABASE, que para mí es lo más inútil de la historia. A menos que estés trabajando en un ambiente realmente extraño, siempre tendrás una base de datos en modo apagado y por lo tanto siempre existirá (y posteriormente la creación de la tabla nunca ocurrirá), prefiero no dar acceso a los usuarios del mundo real para crear una base de datos de todos modos.

De todos modos, he resuelto mi problema específico de querer UserProfile (y tablas relacionadas) para crear la base de datos utilizando el inicializador DropCreateDatabaseIfModelChanges, y obligando a una inicialización, como a continuación:

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

.. esto funciona y es perfecto para el desarrollo, pero es bastante inútil en la práctica, ya que literalmente soltará la base de datos y la volverá a crear desde el principio si el modelo cambia. Para mí, esto hace que toda la práctica del primer código sea casi inútil en su forma predeterminada y probablemente termine revertiendo a una generación de DB-edmx.

El "misterio" detrás de la mesa UserProfile todavía se está creando es que WebSecurity.InitializeDatabaseConnection inicializará la tabla si no existe, no basada en los campos se pasa a ésta, por lo que el EmailAddress fue creado en lugar de UserName, porque lo había cambiado en esto.

+0

Te das cuenta de que esto es para lo que EF Migrations es, ¿correcto? Es inútil porque esa no es la forma de migrar de una versión a otra. EF tiene un caso de uso específico para esto. Además, tu pregunta decía que borraste la base de datos cada vez, cuando parecía que en realidad no la estabas eliminando, pero esperando que EF cambiara mágicamente el esquema por ti. Si realmente nos hubiera dado la información correcta, podríamos haberle dado una respuesta real. Es por eso que te rascaste la cabeza, porque tu pregunta decía que estabas haciendo cosas que no hiciste. –

+0

No estoy seguro de por qué piensas que algo llamado 'CreateDatabase()' en realidad no creó literalmente una base de datos. No es inútil, porque está diseñado para crear la base de datos cuando no existe, que es una situación que nos dijo que era el caso. –

+0

@MystereMan Sí, soy consciente de esto y eso es exactamente lo que resumió mi publicación; ¡un malentendido! En parte se derivaba de otras publicaciones de SO relacionadas con problemas similares donde se decía que 'cambiar la clase actualizaba automáticamente las tablas'. La información que proporcioné en cuanto a "borrar la base de datos" fue, por supuesto, incorrecta ya que en realidad estaba borrando los contenidos de la base de datos *.Mi confusión vino del hecho de que mi tabla 'UserProfile' todavía se estaba creando (aunque de forma incorrecta), pero ahora me doy cuenta de que es la' InitializeDatabaseConnection'. Han sido ** ** muchas semanas largas :) –

47

1 - Debe habilitar las migraciones, preferiblemente con EntityFramework 5. Use Enable-Migrations en el administrador de paquetes NuGet.

2 - Mueva su

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

a tu simiente método en su/Migraciones/Configuración YourMvcApp.clase 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"}); 
    } 

Ahora EF5 estará a cargo de la creación de su mesa de PerfilUsuario, después de hacerlo se le llame a la WebSecurity.InitializeDatabaseConnection al registro de sólo SimpleMembershipProvider con la tabla PerfilUsuario ya creado, también tellling SimpleMembershipProvider qué columna es la identificación de usuario y nombre de usuario También estoy mostrando un ejemplo de cómo puede agregar Usuarios, Roles y asociar los dos en su método Seed con propiedades/campos de UserProfile personalizados, p. Ej. el móvil de un usuario (número).

3 - Ahora al ejecutar update-base de datos desde la consola de Administrador de paquetes, EF5 aprovisionará su mesa con todas sus propiedades personalizadas

Para referencias adicionales, ver este artículo con el código fuente: http://blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties/

+0

No es 100% lo que estaba preguntando, pero ciertamente es 100% útil para otras personas que puedan tener el mismo problema. Disfruta de la recompensa –

+0

gracias, rudi_visser. – LeLong37

+0

FYI, al mover WebSecurity.InitializeDatabaseConnection al método de inicialización se bloquea al actualizar la base de datos de desarrollo (error "La función de administrador de roles no se ha habilitado"). – rufo

2

Estaba teniendo el mismo problema. Agregué el código para que las migraciones se realicen justo antes de "CreateDatabase" en SimpleMembershipInitializer.

Eso solucionó el problema para mí, excepto que creo que ahora mis migraciones se van a aplicar en Azure independientemente de la configuración en el perfil de publicación.

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

Si usted no tiene planes para hacer los cambios una vez que el sistema está vivo y esto sólo ocurre en desarrollo y no dispuestos a permitir que las migraciones. Intente truncar la tabla __MigrationHistory.

truncate table __MigrationHistory 
Cuestiones relacionadas