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