¿Cómo puedo cambiar los nombres de las tablas cuando uso ASP.NET Identity?

213

Estoy usando la versión de lanzamiento (RTM, no RC) de Visual Studio 2013 (descargada de MSDN 2013-10-18) y, por lo tanto, la última versión (RTM) de AspNet.Identity. Cuando creo un nuevo proyecto web, selecciono "Cuentas de usuario individuales" para la autenticación. Esto crea las siguientes tablas:

  1. AspNetRoles
  2. AspNetUserClaims
  3. AspNetUserLogins
  4. AspNetUserRoles
  5. AspNetUsers

Cuando registro un nuevo usuario (usando la plantilla predeterminada), se crean estas tablas (enumeradas anteriormente) y la tabla AspNetUsers tiene un registro insertado que contiene:

  1. Carné de identidad
  2. Nombre de usuario
  3. PasswordHash
  4. Sello de seguridad
  5. Discriminado

Además, al agregar propiedades públicas a la clase "ApplicationUser", he agregado con éxito campos adicionales a la tabla AspNetUsers, como "FirstName", "LastName", "PhoneNumber", etc.

Aquí está mi pregunta. ¿Hay alguna manera de cambiar los nombres de las tablas anteriores (cuando se crean por primera vez) o siempre se nombrarán con el AspNetprefijo que mencioné anteriormente? Si los nombres de las tablas se pueden nombrar de manera diferente, explique cómo.

- ACTUALIZACIÓN -

Implementé la solución de @Hao Kung. Sí crea una nueva tabla (por ejemplo, la llamé MyUsers), pero también crea la tabla AspNetUsers. El objetivo es reemplazar la tabla "AspNetUsers" con la tabla "MyUsers". Vea el código a continuación y la imagen de la base de datos de las tablas creadas.

En realidad, me gustaría reemplazar cada AspNettabla con mi propio nombre ... Por ejemplo, MyRoles, MyUserClaims, MyUserLogins, MyUserRoles y MyUsers.

¿Cómo logro esto y termino con un solo conjunto de tablas?

public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string PostalCode { get; set; }
    public string PhonePrimary { get; set; }
    public string PhoneSecondary { get; set; }
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext(): base("DefaultConnection")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<IdentityUser>().ToTable("MyUsers");
    }
}

Tablas de bases de datos

- ACTUALIZAR RESPUESTA -

Gracias a Hao Kung y Peter Stulinski. Esto resolvió mi problema ...

    protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<IdentityUser>().ToTable("MyUsers").Property(p => p.Id).HasColumnName("UserId");
        modelBuilder.Entity<ApplicationUser>().ToTable("MyUsers").Property(p => p.Id).HasColumnName("UserId");
        modelBuilder.Entity<IdentityUserRole>().ToTable("MyUserRoles");
        modelBuilder.Entity<IdentityUserLogin>().ToTable("MyUserLogins");
        modelBuilder.Entity<IdentityUserClaim>().ToTable("MyUserClaims");
        modelBuilder.Entity<IdentityRole>().ToTable("MyRoles");
    }
usuario2315985
fuente
¿Estás seguro? Elimine todas sus tablas, elimine su tabla _migration y luego intente. El código que he publicado a continuación, que es muy similar al suyo, no crea la tabla AspNetUsers.
Piotr Stulinski
1
La única diferencia entre su código y el mío es que cambié el nombre de ApplicationUser a "Usuario". Mi comportamiento es bastante diferente. En la primera creación, crea las tablas según sea necesario y con los nombres que especifique ... Tal vez solo por "experimentación", intente cambiar ApplicationUser a User y luego agregue las líneas base.OnModelCreating (modelBuilder); modelBuilder.Entity <IdentityUser> () .ToTable ("Usuarios", "dbo"); modelBuilder.Entity <ApplicationUser> () .ToTable ("Usuarios", "dbo");
Piotr Stulinski
1
Solución actualizada arriba ...
user2315985
66
@Daskul Eliminar modelBuilder.Entity <IdentityUser> () .ToTable ("MyUsers"). Propiedad (p => p.Id) .HasColumnName ("UserId"); y en ese caso, la columna discriminadora no se agregará a la tabla MyUsers. Consulte este error para obtener más información: stackoverflow.com/questions/22054168/…
Sergey
1
@ user2315985: debe actualizar su respuesta para eliminar la línea que contiene modelBuilder.Entity<IdentityUser>().ToTable("MyUsers").Property(p => p.Id).HasColumnName("UserId");lo mencionado por @Sergey. De lo contrario, la MyUserstabla recién nombrada tiene una columna discriminadora como señaló @Daskul. Además, la MyUserClaimsestructura de su tabla será incorrecta, como señaló @Matt Overall. Creo que la idea de agregar eso vino de un comentario a @Giang en un blog de msdn , ¡pero está mal!
Kimbaudi

Respuestas:

125

Puede hacerlo fácilmente modificando IdentityModel.cs según lo siguiente:

Anule OnModelCreating en su DbContext y luego agregue lo siguiente, esto cambiará la tabla AspNetUser a "Usuarios", también puede cambiar los nombres de campo, la columna de Id predeterminada se convertirá en User_Id.

modelBuilder.Entity<IdentityUser>()
                    .ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");

o simplemente el siguiente si desea mantener todos los nombres de columna estándar:

modelBuilder.Entity<IdentityUser>()
                        .ToTable("Users", "dbo")

Ejemplo completo a continuación (esto debería estar en su archivo IdentityModel.cs) cambié mi clase ApplicationUser para que se llame Usuario.

public class User : IdentityUser
    {
        public string PasswordOld { get; set; }
        public DateTime DateCreated { get; set; }

        public bool Activated { get; set; }

        public bool UserRole { get; set; }

    }

public class ApplicationDbContext : IdentityDbContext<User>
    {
        public ApplicationDbContext()
            : base("DefaultConnection")
        {
        }

        protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<IdentityUser>()
                .ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
            modelBuilder.Entity<User>()
                .ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
        }
    }

Tenga en cuenta que no he logrado que esto funcione si existe la tabla actual. También tenga en cuenta las columnas que no asigne, se crearán las predeterminadas.

Espero que ayude.

Piotr Stulinski
fuente
2
Para que estos cambios surtan efecto, debe usar migraciones para enviar los cambios a la base de datos existente.
Lukasz
2
Si hace esto, sus claves externas serán un poco extrañas, no creo que deba cambiar el nombre de la tabla en IdentityUser. Ver esta publicación SO
Matt En general, el
Solo como un cheque extra ya que esto me atrapó anteriormente. Asegúrese de que la llamada a base.OnModelCreatingsea ​​la primera línea de código en la anulación; de lo contrario, el resto de las líneas serán sobrescritas por la clase de identidad base.
DavidG
@DavidG Gracias de verdad
SA
Buena solución. Pero no es necesario sobrescribir el nombre de la tabla para IdentityUser. Vea esta solución stackoverflow.com/questions/28016684/…
EJW
59

A continuación se muestra mi solución de trabajo:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder); // This needs to go before the other rules!

        modelBuilder.Entity<ApplicationUser>().ToTable("User");
        modelBuilder.Entity<IdentityRole>().ToTable("Role");
        modelBuilder.Entity<IdentityUserRole>().ToTable("UserRole");
        modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaim");
        modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogin");
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

Mira esto para más detalles

Frank Myat Thu
fuente
¿Puedes hacerlo especificando atributos en lugar de la (fea) API fluida?
Mariusz Jamro
¡Hice una edición menor ya que de alguna manera logré rechazar esta respuesta y no me di cuenta! También lo actualicé para usar el método preferido para enlaces como este[text](link)
DavidG
Creé un proyecto MVC vacío, lo ejecuté 1 vez y se crearon las tablas con nombre asp. Luego agregué este cambio menor, eliminé todas mis tablas y la carpeta de migración (para lo que vale) y ejecuté mi código nuevamente, pero las tablas se negaron a cambiar de nombre. Luego creé un proyecto completamente nuevo, hice este cambio antes de ejecutarlo, y ahora está funcionando. ¿Me estoy perdiendo algo muy obvio?
mathkid91
15

Puede intentar anular este método en su clase DbContext para asignarlo a una tabla de su elección:

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        modelBuilder.Entity<IdentityUser>()
            .ToTable("AspNetUsers");
Hao Kung
fuente
77
No olvides llamar base.OnModelCreating(modelBuilder);o el resto del modelo no se creará.
Ferruccio
Actualicé mi pregunta después de implementar la solución de @Hao Kung pero el problema persiste, vea mi pregunta editada arriba. Gracias.
user2315985
1

También puede crear clases de configuración y especificar cada detalle de cada una de sus clases de identidad, por ejemplo:

using System.Data.Entity.ModelConfiguration;

public class ApplicationUserConfig : EntityTypeConfiguration<ApplicationUser>
{
    public UserConfig()
    {
        ToTable("Users");
        Property(u => u.LocationName).IsRequired();
    }
}

Y luego incluya estas configuraciones en el método OnModelCreating ():

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Configurations.Add(new ApplicationUserConfig());
        ...
    }

Esto le dará un control completo sobre cada aspecto de las clases de identidad.

Manish
fuente
1

Solo para fines de documentación, para el que llega a esta publicación en los años que tenga años en el futuro, (como yo XD), todas las respuestas dadas en mi comentario son correctas, pero puede simplemente usar este método dado por Alexandru Bucur en su blog

         //But this method is not longer supported on netcore > 2.2, so I need to fix it
         foreach (var entityType in modelBuilder.Model.GetEntityTypes())
         {
            var table = entityType.Relational().TableName;
             if (table.StartsWith("AspNet"))
             {
                 entityType.Relational().TableName = table.Substring(6);
             }
         };

        //This is the functional way on NetCore > 2.2
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            var tableName = entityType.GetTableName();
            if (tableName.StartsWith("AspNet"))
            {
                entityType.SetTableName(tableName.Substring(6));
            }
        }
sgrysoft
fuente
0

Podemos cambiar los nombres de tabla predeterminados de Identidad asp.net de esta manera:

    public class ApplicationDbContext : IdentityDbContext
    {    
        public ApplicationDbContext(): base("DefaultConnection")
        {
        }

        protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<IdentityUser>().ToTable("user");
            modelBuilder.Entity<ApplicationUser>().ToTable("user");

            modelBuilder.Entity<IdentityRole>().ToTable("role");
            modelBuilder.Entity<IdentityUserRole>().ToTable("userrole");
            modelBuilder.Entity<IdentityUserClaim>().ToTable("userclaim");
            modelBuilder.Entity<IdentityUserLogin>().ToTable("userlogin");
        }
    }

Además, podemos extender cada clase y agregar cualquier propiedad a clases como 'IdentityUser', 'IdentityRole', ...

    public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
    public ApplicationRole() 
    {
        this.Id = Guid.NewGuid().ToString();
    }

    public ApplicationRole(string name)
        : this()
    {
        this.Name = name;
    }

    // Add any custom Role properties/code here
}


// Must be expressed in terms of our custom types:
public class ApplicationDbContext 
    : IdentityDbContext<ApplicationUser, ApplicationRole, 
    string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }

    static ApplicationDbContext()
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    // Add additional items here as needed
}

Para ahorrar tiempo, podemos usar la plantilla de proyecto extensible AspNet Identity 2.0 para extender todas las clases.

Arvand
fuente
0

Pero no funciona en .NET CORE (MVC 6) para eso necesitamos cambiar el enlace a

me gusta

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    builder.Entity<IdentityRole>().ToTable("Role");
    builder.Entity<IdentityUser>(entity => 
    {
        entity.ToTable("User");
        entity.Property(p => p.Id).HasColumnName("UserId");
    });
}

Podría ayudar a alguien :)

dnxit
fuente
¿Funciona esto tanto para code-first como para database-first?
liang
No he probado primero la base de datos, pero supongo que debería funcionar si el modelo y la base de datos son iguales.
dnxit