web-dev-qa-db-fra.com

Comment faire pour que EF-Core utilise un Guid au lieu de String pour son ID / clé primaire

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 Frameworkcode 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 2ENtity 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.

19
devfric

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

41
tmg

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();
9
Ron DeFreitas

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.

2
Joe Audette