Comment puis-je changer les noms de table lors de l'utilisation de l'identité ASP.NET?

213

J'utilise la version finale (RTM, pas RC) de Visual Studio 2013 (téléchargée à partir de MSDN 2013-10-18) et donc la dernière version (RTM) d'AspNet.Identity. Lorsque je crée un nouveau projet Web, je sélectionne "Comptes d'utilisateurs individuels" pour l'authentification. Cela crée les tableaux suivants:

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

Lorsque j'enregistre un nouvel utilisateur (en utilisant le modèle par défaut), ces tables (répertoriées ci-dessus) sont créées et la table AspNetUsers a un enregistrement inséré qui contient:

  1. Id
  2. Nom d'utilisateur
  3. PasswordHash
  4. SecurityStamp
  5. Discriminateur

De plus, en ajoutant des propriétés publiques à la classe "ApplicationUser", j'ai réussi à ajouter des champs supplémentaires à la table AspNetUsers, tels que "FirstName", "LastName", "PhoneNumber", etc.

Voici ma question. Existe-t-il un moyen de changer les noms des tables ci-dessus (lors de leur première création) ou seront-ils toujours nommés avec le AspNetpréfixe comme indiqué ci-dessus? Si les noms de table peuvent être nommés différemment, veuillez expliquer comment.

-- METTRE À JOUR --

J'ai implémenté la solution de @Hao Kung. Il crée une nouvelle table (par exemple, je l'ai appelée MyUsers), mais il crée également la table AspNetUsers. L'objectif est de remplacer la table "AspNetUsers" par la table "MyUsers". Voir le code ci-dessous et l'image de base de données des tables créées.

J'aimerais en fait remplacer chaque AspNettable par mon propre nom ... Par exemple, MyRoles, MyUserClaims, MyUserLogins, MyUserRoles et MyUsers.

Comment puis-je accomplir cela et me retrouver avec un seul ensemble de tables?

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

Tables de base de données

- RÉPONSE DE MISE À JOUR -

Merci à Hao Kung et Peter Stulinski. Cela a résolu mon problème ...

    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
la source
Êtes-vous sûr? Veuillez supprimer toutes vos tables, supprimez votre table de _migration, puis essayez. Le code que j'ai publié ci-dessous, qui est très similaire au vôtre, ne crée pas la table AspNetUsers.
Piotr Stulinski
1
La seule différence entre votre code et le mien est que j'ai renommé ApplicationUser en "Utilisateur". Mon comportement est assez différent. Lors de la première création, il crée les tables selon les besoins et avec les noms que je spécifie. modelBuilder.Entity <IdentityUser> () .ToTable ("Users", "dbo"); modelBuilder.Entity <ApplicationUser> () .ToTable ("Users", "dbo");
Piotr Stulinski
1
Solution mise à jour ci-dessus ...
user2315985
6
@Daskul Remove modelBuilder.Entity <IdentityUser> () .ToTable ("MyUsers"). Property (p => p.Id) .HasColumnName ("UserId"); et dans ce cas, la colonne discriminante ne sera pas ajoutée à la table MyUsers. Voir cette erreur pour plus d'informations: stackoverflow.com/questions/22054168/…
Sergey
1
@ user2315985 - Vous devez mettre à jour votre réponse pour supprimer la ligne contenant modelBuilder.Entity<IdentityUser>().ToTable("MyUsers").Property(p => p.Id).HasColumnName("UserId");comme mentionné par @Sergey. Sinon, la MyUserstable nouvellement nommée a une colonne discriminante comme l'a souligné @Daskul. De plus, la MyUserClaimsstructure de votre table sera erronée comme l'a souligné @Matt Global. Je pense que l'idée d'ajouter cela est venue d'un commentaire à @Giang dans un blog msdn , mais c'est faux!
kimbaudi

Réponses:

125

Vous pouvez le faire facilement en modifiant le IdentityModel.cs comme ci-dessous:

Remplacez OnModelCreating dans votre DbContext puis ajoutez ce qui suit, cela changera la table AspNetUser en "Utilisateurs", vous pouvez également changer les noms de champ, la colonne Id par défaut deviendra User_Id.

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

ou simplement ci-dessous si vous souhaitez conserver tous les noms de colonnes standard:

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

Exemple complet ci-dessous (cela devrait être dans votre fichier IdentityModel.cs) J'ai changé ma classe ApplicationUser pour être appelée User.

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

Veuillez noter que je n'ai pas réussi à faire fonctionner cela si la table actuelle existe. Notez également que les colonnes que vous ne mappez pas seront créées par défaut.

J'espère que cela pourra aider.

Piotr Stulinski
la source
2
Pour que ces modifications prennent effet, vous devez utiliser les migrations pour transférer les modifications vers la base de données existante.
Lukasz
2
Si vous faites cela, vos clés étrangères seront un peu bizarres, je ne pense pas que vous soyez obligé de changer le nom de la table sur IdentityUser. Voir ce message SO
Matt dans l'ensemble
Tout comme un contrôle supplémentaire, car cela m'a attrapé précédemment. Assurez-vous que l'appel à base.OnModelCreatingest la première ligne de code dans le remplacement sinon les autres lignes sont écrasées par la classe d'identité de base.
DavidG
@DavidG Merci en effet
SA
Bonne solution. Mais il n'est pas nécessaire d'écraser le nom de la table pour IdentityUser. Voir cette solution stackoverflow.com/questions/28016684/…
EJW
59

Voici ma solution de travail:

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

Voir ceci pour plus de détails

Frank Myat Thu
la source
Pouvez-vous faire cela en spécifiant des attributs au lieu de l'api fluide (moche)?
Mariusz Jamro
J'ai fait une modification mineure car j'ai réussi à dévaloriser cette réponse et je n'ai pas remarqué! Également mis à jour pour utiliser la méthode préférée pour des liens comme celui-ci[text](link)
DavidG
J'ai créé un projet MVC vide, l'ai exécuté 1 fois et les tables nommées asp ont été créées. Ensuite, j'ai ajouté cette modification mineure, supprimé toutes mes tables et le dossier de migration (pour ce que ça vaut) et j'ai exécuté à nouveau mon code, mais les tables ont refusé d'être renommées. J'ai ensuite créé un projet entièrement nouveau, effectué ce changement avant de lancer, et maintenant son fonctionnement. Suis-je en train de manquer quelque chose de très évident ??
mathkid91
15

Vous pouvez essayer de remplacer cette méthode dans votre classe DbContext pour la mapper à une table de votre choix:

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        modelBuilder.Entity<IdentityUser>()
            .ToTable("AspNetUsers");
Hao Kung
la source
7
N'oubliez pas d'appeler base.OnModelCreating(modelBuilder);ou le reste du modèle ne sera pas créé.
Ferruccio
J'ai mis à jour ma question après avoir implémenté la solution de @Hao Kung mais le problème persiste, veuillez consulter ma question modifiée ci-dessus. Merci.
user2315985
1

Vous pouvez également créer des classes de configuration et spécifier chaque détail de chacune de vos classes d'identité, par exemple:

using System.Data.Entity.ModelConfiguration;

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

Et puis incluez ces configurations dans la méthode OnModelCreating ():

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

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

Cela vous donnera un contrôle complet sur tous les aspects des classes d'identité.

Manish
la source
1

Juste à des fins de documentation, pour celui qui vient à ce poste sur les années à venir, (comme moi XD), toutes les réponses données à mon commentaire sont exactes, mais vous pouvez simplement vous fier à cette méthode donnée par Alexandru Bucur sur son 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
la source
0

Nous pouvons changer les noms de table par défaut de asp.net Identity comme ceci:

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

De plus, nous pouvons étendre chaque classe et ajouter n'importe quelle propriété à des classes comme '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
}

Pour gagner du temps, nous pouvons utiliser le modèle de projet extensible AspNet Identity 2.0 pour étendre toutes les classes.

Arvand
la source
0

Mais cela ne fonctionne pas dans .NET CORE (MVC 6) pour cela, nous devons changer la liaison en

comme

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

Cela pourrait aider quelqu'un :)

dnxit
la source
cela fonctionne-t-il pour le code en premier et pour la base de données en premier?
liang
Je n'ai pas essayé la base de données en premier, mais je suppose que cela devrait fonctionner si le modèle et la base de données sont identiques.
dnxit