Como posso alterar os nomes das tabelas ao usar a identidade do ASP.NET?

213

Estou usando a versão de lançamento (RTM, não RC) do Visual Studio 2013 (baixado do MSDN 2013-10-18) e, portanto, a versão mais recente (RTM) do AspNet.Identity. Quando crio um novo projeto da web, seleciono "Contas de usuário individuais" para autenticação. Isso cria as seguintes tabelas:

  1. AspNetRoles
  2. AspNetUserClaims
  3. AspNetUserLogins
  4. AspNetUserRoles
  5. Usuários AspNet

Quando eu registro um novo usuário (usando o modelo padrão), essas tabelas (listadas acima) são criadas e a tabela AspNetUsers possui um registro inserido que contém:

  1. Eu iria
  2. Nome do usuário
  3. PasswordHash
  4. SecurityStamp
  5. Discriminador

Além disso, adicionando propriedades públicas à classe "ApplicationUser", adicionei campos adicionais à tabela AspNetUsers, como "FirstName", "LastName", "PhoneNumber" etc.

Aqui está a minha pergunta. Existe uma maneira de alterar os nomes das tabelas acima (quando elas são criadas pela primeira vez) ou elas sempre serão nomeadas com o AspNetprefixo conforme listado acima? Se os nomes das tabelas puderem ter nomes diferentes, explique como.

- ATUALIZAÇÃO -

Implementei a solução de @Hao Kung. Ele cria uma nova tabela (por exemplo, eu a chamei de MyUsers), mas também cria a tabela AspNetUsers. O objetivo é substituir a tabela "AspNetUsers" pela tabela "MyUsers". Veja o código abaixo e a imagem do banco de dados das tabelas criadas.

Na verdade, gostaria de substituir cada AspNettabela por meu próprio nome ... Por exemplo, MyRoles, MyUserClaims, MyUserLogins, MyUserRoles e MyUsers.

Como faço isso e acabo com apenas um conjunto de tabelas?

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

Tabelas de banco de dados

- ATUALIZAR RESPOSTA -

Agradecimentos a Hao Kung e Peter Stulinski. Isso resolveu meu 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");
    }
user2315985
fonte
Você tem certeza? Exclua todas as suas tabelas, remova sua tabela _migration e tente. O código que publiquei abaixo, que é muito semelhante ao seu, não cria a tabela AspNetUsers.
Piotr Stulinski
1
A única diferença entre o seu código e o meu é que renomeei o ApplicationUser para "User". Meu comportamento é bem diferente. Na primeira criação, ele cria as tabelas conforme necessário e com os nomes que eu especifico ... Talvez apenas por "experimentação", tente alterar ApplicationUser para User e adicione as linhas base.OnModelCreating (modelBuilder); modelBuilder.Entity <IdentityUser> () .ToTable ("Usuários", "dbo"); modelBuilder.Entity <ApplicationUser> () .ToTable ("Usuários", "dbo");
Piotr Stulinski
1
Solução atualizada acima ...
user2315985 30/10
6
@Daskul Remover modelBuilder.Entity <IdentityUser> () .ToTable ("MyUsers"). Propriedade (p => p.Id) .HasColumnName ("UserId"); e, nesse caso, a coluna discriminadora não será adicionada à tabela MyUsers. Veja este erro para obter mais informações: stackoverflow.com/questions/22054168/…
Sergey
1
@ user2315985 - Você deve atualizar sua resposta para remover a linha que contém modelBuilder.Entity<IdentityUser>().ToTable("MyUsers").Property(p => p.Id).HasColumnName("UserId");as mencionadas por @Sergey. Caso contrário, a MyUserstabela recém nomeada possui uma coluna discriminadora, como @Daskul apontou. Além disso, a MyUserClaimsestrutura da sua tabela estará incorreta como o @Matt Overall apontou. Eu acho que a ideia de adicionar isso veio de um comentário para @Giang em um blog msdn , mas está errado!
Kimbaudi 13/10/16

Respostas:

125

Você pode fazer isso facilmente modificando o IdentityModel.cs conforme abaixo:

Substitua OnModelCreating no seu DbContext e adicione o seguinte, isso mudará a tabela AspNetUser para "Users". Você também pode alterar os nomes dos campos nos quais a coluna Id padrão se tornará User_Id.

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

ou simplesmente o abaixo, se você deseja manter todos os nomes de colunas padrão:

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

Exemplo completo abaixo (isso deve estar no seu arquivo IdentityModel.cs). Alterei minha classe ApplicationUser para ser chamada de Usuário.

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

Observe que não consegui fazer isso funcionar se a tabela atual existir. Observe também as colunas que você não mapeia, as colunas padrão serão criadas.

Espero que ajude.

Piotr Stulinski
fonte
2
Para que essas alterações entrem em vigor, é necessário usar migrações para enviar as alterações ao banco de dados existente.
Lukasz
2
Se você fizer isso, suas chaves estrangeiras serão um pouco estranhas, não acho que você precise alterar o nome da tabela no IdentityUser. Veja este post no SO
Matt Geral
Apenas como uma verificação extra, pois isso me chamou a atenção anteriormente. Verifique se a chamada para base.OnModelCreatingé a primeira linha de código na substituição, caso contrário, as demais linhas serão substituídas pela classe Identity base.
DavidG 22/01
@DavidG Thank you really
SA
Boa solução. Mas não é necessário substituir o nome da tabela para IdentityUser. Veja esta solução stackoverflow.com/questions/28016684/…
EJW 11/11/17
59

Abaixo está minha solução de trabalho:

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

Veja isto para mais detalhes

Frank Myat Thu
fonte
Você pode fazer isso especificando atributos em vez da API (feia) fluente?
Mariusz Jamro
Fiz uma edição menor, pois de alguma forma eu consegui votar esta resposta e não percebi! Também atualizado para usar o método preferido para links como este[text](link)
DavidG
Criei um projeto MVC vazio, executei-o uma vez e as tabelas nomeadas asp foram criadas. Em seguida, adicionei essa pequena alteração, excluí todas as minhas tabelas e pastas de migração (pelo que vale a pena) e executei meu código novamente, mas as tabelas se recusaram a ser renomeadas. Criei um projeto totalmente novo, fiz essa alteração antes de executar e agora está funcionando. Estou perdendo algo muito óbvio?
mathkid91
15

Você pode tentar substituir esse método na sua classe DbContext para mapeá-lo para uma tabela de sua escolha:

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        modelBuilder.Entity<IdentityUser>()
            .ToTable("AspNetUsers");
Hao Kung
fonte
7
Não se esqueça de ligar base.OnModelCreating(modelBuilder);ou o restante do modelo não será criado.
Ferruccio
Atualizei minha pergunta depois de implementar a solução de @Hao Kung, mas o problema persistir, consulte minha pergunta editada acima. Obrigado.
user2315985
1

Você também pode criar classes de configuração e especificar todos os detalhes de cada uma das suas classes de identidade, por exemplo:

using System.Data.Entity.ModelConfiguration;

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

E inclua estas configurações no método OnModelCreating ():

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

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

Isso lhe dará controle completo sobre todos os aspectos das classes Identity.

Manish
fonte
1

Apenas para fins de documentação, para quem vem a este post sobre os próximos anos no futuro (como eu, XD), todas as respostas dadas no meu comentário estão corretas, mas você pode simplesmente brincar com esse método dado por Alexandru Bucur em seu 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
fonte
0

Podemos alterar os nomes de tabela padrão da identidade do asp.net assim:

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

Além disso, podemos estender cada classe e adicionar qualquer propriedade a classes 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 economizar tempo, podemos usar o modelo de projeto extensível do AspNet Identity 2.0 para estender todas as classes.

Arvand
fonte
0

Mas ele não funciona no .NET CORE (MVC 6), pelo que precisamos alterar a ligação para

gostar

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

Pode ajudar alguém :)

dnxit
fonte
isso funciona para o código primeiro e o banco de dados primeiro?
liang
Eu não tentei primeiro o banco de dados, mas acho que deve funcionar se o modelo e o banco de dados forem iguais.
dnxit 29/07/19