with net existing customize asp asp.net-core asp.net-identity entity-framework-core asp.net-identity-3

asp.net-core - existing - asp.net core identity



Cómo hacer que EF-Core use un Guid en lugar de String para su ID/clave principal (3)

Cuando miro la identidad de ASP.NET 3, utiliza una string y no un Guid para la clave principal única.

En mi code first Entity Framework code first la clase ApplicationUser los usuarios, heredé la clase Identity.

public class ApplicationUser : IdentityUser { }

que se traduce en que cuando creo mis migraciones de Entity Framework, una tabla y aspnetusers se crean con un tipo de clave de nvarchar(450) lugar de un uniqueidentifier

Cuando comparo esto con el proyecto ASP.NET Identity 2 ENtity Framework , se creó un campo de ID de identificador uniqueidentifier y no nvarchar(450)

Me imagino que para el rendimiento de la base de datos, las claves primarias y las claves externas del uniqueidentifier serían mejores que nvarchar(450)

¿Hay alguna forma de usar la clave única Guid lugar de string e uniqueidentifier lugar de nvarchar(450) con ASP.NET Identity 3 ?

Hay una pregunta anterior sobre cómo convertir una cadena en un Guid, pero quiero que el ID de la tabla de la base de datos sea un Guid.

También encontré otra question para un BETA anterior cuando la longitud era nvarchar (128). La razón dada es que no todas las bases de datos admiten Guids y se cambió por flexibilidad.

¿Debe haber una manera fácil de cambiar de cadena a Guid sin volver a escribir toda la identity 3 ?

nvarchar(450) es realmente excesivo y da todo tipo de advertencias al crear restricciones de base de datos de SQL Server. A los administradores de bases de datos definitivamente no les gustarán estas advertencias.


Aún no me he metido con las migraciones para este ejemplo (es posible que necesiten algunos ajustes), sin embargo, ASP.NET Identity v3 es mucho más extensible que v2 en este sentido.

Lo siguiente debería proporcionarle un almacén de identidad basado en las claves primarias de Guid para usuarios y roles por igual:

public class ApplicationUser : IdentityUser<Guid> { } public class GuidDataContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid> { }

y en tu clase de inicio:

services.AddIdentity<ApplicationUser, IdentityRole<Guid>>( identity => { // whatever identity options you want identity.User.RequireUniqueEmail = true; identity.Password.RequiredLength = 8; }). AddEntityFrameworkStores<GuidDataContext, Guid>().AddDefaultTokenProviders();

Del mismo modo, si no era necesario agregar campos personalizados al Usuario de Identidad, o personalizar sus opciones, podría hacer lo siguiente:

public class GuidDataContext : IdentityDbContext<IdentityUser<Guid>, IdentityRole<Guid>, Guid> { }

y en tu startup:

services .AddIdentity<IdentityUser<Guid>, IdentityRole<Guid>>() .AddEntityFrameworkStores<GuidDataContext, Guid>() .AddDefaultTokenProviders();


ApplicationUser hereda de la clase base IdentityUser que se define como tener una cadena como id. Por lo tanto, para usar realmente un guid / identificador único, necesitaría no heredar de esa clase base.

Tenga en cuenta que internamente está utilizando cadenas guid para identificadores. Al menos debería poder limitar el tamaño del campo de la clave como se muestra aquí:

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

Es posible usar Guids / uniqueidentifier para la clave, pero eso requerirá más trabajo, además de usar su propia clase base (o no usar una clase base) y usar un DbContext personalizado para mapear el modelo. Tomar prestado y modificar el código de EF desde aquí debería UserStore , tendría que heredar de UserStore y anular los métodos virtuales para buscar un usuario por id, porque la interfaz IUserStore define la firma del método FindById con una cadena. Por lo tanto, para anular la conversión, debe convertir la cadena en un guid dentro de los métodos en los que necesita buscar o buscar por ID.

Estoy haciendo exactamente eso en mi proyecto de CloudScribe, que tiene una implementación personalizada de Identity para varios usuarios.

EDITAR: en realidad, mirando más de cerca el código, el IdentityUser tiene una versión genérica donde puede definir el tipo de clave

public class IdentityUser<TKey> where TKey : IEquatable<TKey>

Así que quizás puedas definir tu propia clase base como

IdentityUser<Guid>

pero sigo pensando que necesitarías anular los métodos de UserStore que toman una cadena de identificación y convierten la cadena en un guid.


Necesita una ApplicationUser de IdentityUser<TKey> personalizada IdentityUser<TKey> de IdentityUser<TKey> y una función personalizada IdentityRole<TKey> de IdentityRole<TKey>

public class ApplicationUser : IdentityUser<Guid> { } public class Role : IdentityRole<Guid> { }

La clase de contexto personalizada se hereda de IdentityDbContext<ApplicationUser, Role, TKey> y usa una API fluida para generar claves de IdentityDbContext<ApplicationUser, Role, TKey> automáticamente.

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

Luego, en Inicio, agregue el servicio de identidad al contenedor como este.

services.AddIdentity<ApplicationUser, Role>() .AddEntityFrameworkStores<ApplicationDbContext, Guid>() .AddDefaultTokenProviders() .AddUserStore<UserStore<ApplicationUser, Role, ApplicationDbContext, Guid>> () .AddRoleStore<RoleStore<Role, ApplicationDbContext, Guid>>();

Si no ha creado la base de datos, borre la carpeta de migraciones y ejecute los comandos ef