How to make EF-Core use a Guid instead of String for its ID/Primary key
Solution 1
You need custom ApplicationUser
inherit from IdentityUser<TKey>
and custom Role inherit from IdentityRole<TKey>
public class ApplicationUser : IdentityUser<Guid> { }
public class Role : IdentityRole<Guid> { }
Custom context class inherit from IdentityDbContext<ApplicationUser, Role, TKey>
and use fluent api for auto generate guid keys.
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()");
});
}
}
then in Startup add Identity service to container like this
services.AddIdentity<ApplicationUser, Role>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders()
.AddUserStore<UserStore<ApplicationUser, Role, ApplicationDbContext, Guid>> ()
.AddRoleStore<RoleStore<Role, ApplicationDbContext, Guid>>();
If you have not created the database, clear the migrations folder and run ef commands
Solution 2
I haven't messed with the migrations for this example yet (they might need some tweaks), however ASP.NET Identity v3 is far more extensible than v2 was in this regard.
The following should give you an Identity store based on Guid primary keys for Users and Roles alike:
public class ApplicationUser : IdentityUser<Guid>
{
}
public class GuidDataContext :
IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
{
}
and in your startup class:
services.AddIdentity<ApplicationUser, IdentityRole<Guid>>(
identity =>
{
// whatever identity options you want
identity.User.RequireUniqueEmail = true;
identity.Password.RequiredLength = 8;
}).
AddEntityFrameworkStores<GuidDataContext, Guid>().AddDefaultTokenProviders();
Likewise, if you didn't need to add any custom fields to the Identity User, or customize your options, you could just do the following:
public class GuidDataContext :
IdentityDbContext<IdentityUser<Guid>, IdentityRole<Guid>, Guid>
{
}
and in your startup:
services
.AddIdentity<IdentityUser<Guid>, IdentityRole<Guid>>()
.AddEntityFrameworkStores<GuidDataContext, Guid>()
.AddDefaultTokenProviders();
Solution 3
ApplicationUser inherits from IdentityUser base class which is defined as having a string as id. So to really use a guid/uniqueidentifier you would need to not inherit from that base class.
Note that internally it is using guid strings for ids. You should at least be able to limit the field size of the key like shown here:
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();
});
}
}
It is possible to use Guids/uniqueidentifier for the key but that will require more work, in addition to using your own base class (or not use a base class at all) and use a custom DbContext to map the model. Borrowing and modifying the EF code from here should get you going, you would have to inherit from UserStore and override the virtual methods for looking up a user by id, because the interface IUserStore defines the FindById method signature with a string. So overriding you would need to convert the string to a guid inside the methods where you need to fetch or find by id.
I'm doing exactly that in my cloudscribe project which has a custom multi-tenant implementation of Identity
EDIT: actually looking closer at the code the IdentityUser has a generic version where you can define the type of the key
public class IdentityUser<TKey> where TKey : IEquatable<TKey>
So you might be able to just define your own base class like
IdentityUser<Guid>
but I still think you would need to override the UserStore methods that take an id string and convert the string to a guid.
Comments
-
devfric over 3 years
When I look at the ASP.NET 3 Identity it uses a
string
and not aGuid
for the unique primary key.In my
Entity Framework
code first
Users'ApplicationUser
class I inherit the Identity classpublic class ApplicationUser : IdentityUser { }
which results in when I create my Entity Framework migrations a table
aspnetusers
getting created with a key type ofnvarchar(450)
instead ofuniqueidentifier
When I compare this to
ASP.NET Identity 2
ENtity Framework
project it created an ID field ofuniqueidentifier
and notnvarchar(450)
I would imagine for database performance primary keys and foreign keys of
uniqueidentifier
would be better thannvarchar(450)
Is there a way to use for the unique key
Guid
instead ofstring
anduniqueidentifier
instead ofnvarchar(450)
withASP.NET Identity 3
?There is a previous question how to convert a String to a Guid but I want the database table Id to be a Guid.
I found another question as well for a previous BETA when the length was nvarchar(128). The reason given is that not all databases support Guids and it was changed for flexibility.
Is there must be an easy way to change from string to Guid without rewriting the whole
identity 3
?nvarchar(450)
is really overkill and gives all kinds of warnings when creating SQL Server database constraints. Database admins will definitively not like these warnings.