Lorsque je regarde l'identité ASP.NET 3, elle utilise un string
et non un Guid
pour la clé primaire unique.
Dans ma classe Entity Framework
code first
Utilisateurs ApplicationUser
j'hérite de la classe Identity
public class ApplicationUser : IdentityUser
{
}
ce qui signifie que lorsque je crée mes migrations Entity Framework, une table aspnetusers
est créée avec un type de clé denvarchar(450)
au lieu de uniqueidentifier
Lorsque je compare cela au projet ASP.NET Identity 2
ENtity Framework
, Il crée un champ ID de uniqueidentifier
et non nvarchar(450)
J'imagine que pour les performances des bases de données, les clés primaires et les clés étrangères de uniqueidentifier
seraient mieux que nvarchar(450)
Existe-t-il un moyen d'utiliser la clé unique Guid
au lieu de string
et uniqueidentifier
au lieu de nvarchar(450)
avec ASP.NET Identity 3
?
Il y a question précédente comment convertir une chaîne en Guid mais je veux que l'ID de la table de base de données soit un Guid.
J'en ai trouvé un autre question aussi pour un BETA précédent quand la longueur était nvarchar (128). La raison invoquée est que toutes les bases de données ne prennent pas en charge Guids et il a été modifié pour plus de flexibilité.
Existe-t-il un moyen facile de passer de la chaîne à Guid sans réécrire l'ensemble identity 3
?
nvarchar(450)
est vraiment exagéré et donne toutes sortes d'avertissements lors de la création de contraintes de base de données SQL Server. Les administrateurs de bases de données n'aimeront définitivement pas ces avertissements.
Vous avez besoin d'un ApplicationUser
personnalisé hérité de IdentityUser<TKey>
et le rôle personnalisé héritent de IdentityRole<TKey>
public class ApplicationUser : IdentityUser<Guid> { }
public class Role : IdentityRole<Guid> { }
Classe de contexte personnalisée héritée de IdentityDbContext<ApplicationUser, Role, TKey>
et utilisez une api courante pour générer automatiquement les touches guid.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, Role, Guid>
{
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>(b =>
{
b.Property(u => u.Id).HasDefaultValueSql("newsequentialid()");
});
builder.Entity<Role>(b =>
{
b.Property(u => u.Id).HasDefaultValueSql("newsequentialid()");
});
}
}
puis dans le démarrage, ajoutez le service d'identité au conteneur comme celui-ci
services.AddIdentity<ApplicationUser, Role>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders()
.AddUserStore<UserStore<ApplicationUser, Role, ApplicationDbContext, Guid>> ()
.AddRoleStore<RoleStore<Role, ApplicationDbContext, Guid>>();
Si vous n'avez pas créé la base de données, videz le dossier migrations et exécutez les commandes ef
Je n'ai pas encore dérangé les migrations pour cet exemple (elles pourraient avoir besoin de quelques ajustements), mais ASP.NET Identity v3 est beaucoup plus extensible que la v2 à cet égard.
Les éléments suivants devraient vous fournir un magasin d'identité basé sur les clés primaires Guid pour les utilisateurs et les rôles:
public class ApplicationUser : IdentityUser<Guid>
{
}
public class GuidDataContext :
IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
{
}
et dans votre classe de démarrage:
services.AddIdentity<ApplicationUser, IdentityRole<Guid>>(
identity =>
{
// whatever identity options you want
identity.User.RequireUniqueEmail = true;
identity.Password.RequiredLength = 8;
}).
AddEntityFrameworkStores<GuidDataContext, Guid>().AddDefaultTokenProviders();
De même, si vous n'avez pas besoin d'ajouter de champs personnalisés à l'utilisateur d'identité ou de personnaliser vos options, vous pouvez simplement effectuer les opérations suivantes:
public class GuidDataContext :
IdentityDbContext<IdentityUser<Guid>, IdentityRole<Guid>, Guid>
{
}
et dans votre startup:
services
.AddIdentity<IdentityUser<Guid>, IdentityRole<Guid>>()
.AddEntityFrameworkStores<GuidDataContext, Guid>()
.AddDefaultTokenProviders();
ApplicationUser hérite de IdentityUser classe de base qui est définie comme ayant une chaîne comme id. Donc, pour vraiment utiliser un identifiant guid/unique, vous ne devez pas hériter de cette classe de base.
Notez qu'en interne, il utilise des chaînes de guidage pour les identifiants. Vous devriez au moins pouvoir limiter la taille du champ de la clé comme illustré ici:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>(b =>
{
// you could limit the field size to just long enough for a guid id as string
b.Property(p => p.Id)
.HasMaxLength(36);
// instead, you could define the id as Guid but more work required
//b.Property(p => p.Id)
// .ForSqlServerHasColumnType("uniqueidentifier")
// .ForSqlServerHasDefaultValueSql("newid()")
// .IsRequired();
});
}
}
Il est possible d'utiliser Guids/uniqueidentifier pour la clé, mais cela nécessitera plus de travail, en plus d'utiliser votre propre classe de base (ou de ne pas utiliser de classe de base du tout) et d'utiliser un DbContext personnalisé pour mapper le modèle. Emprunter et modifier le code EF d'ici devrait vous permettre de continuer, vous devrez hériter de serStore et remplacer les méthodes virtuelles pour rechercher un utilisateur par id, car l'interface IUserStore définit la signature de la méthode FindById avec une chaîne. Donc, vous devez remplacer la chaîne en un guid à l'intérieur des méthodes où vous devez aller chercher ou trouver par id.
Je fais exactement cela dans mon projet cloudscribe qui a une implémentation personnalisée multi-locataire d'Identity
EDIT: en regardant de plus près le code, IdentityUser a une version générique où vous pouvez définir le type de la clé
public class IdentityUser<TKey> where TKey : IEquatable<TKey>
Ainsi, vous pourrez peut-être simplement définir votre propre classe de base comme
IdentityUser<Guid>
mais je pense toujours que vous devrez remplacer les méthodes UserStore qui prennent une chaîne id et convertissent la chaîne en guid.