如何使 EF-Core 使用 Guid 而不是 String 作为其 ID/Primary 键
How to make EF-Core use a Guid instead of String for its ID/Primary key
当我查看 ASP.NET 3 Identity 时,它使用 string
而不是 Guid
作为唯一主键。
在我的 Entity Framework
code first
用户的 ApplicationUser
class 我继承了身份 class
public class ApplicationUser : IdentityUser
{
}
这导致当我创建我的 Entity Framework 迁移时,一个 table aspnetusers
被创建时使用的密钥类型是 nvarchar(450)
而不是 uniqueidentifier
当我将其与 ASP.NET Identity 2
ENtity Framework
项目进行比较时,它创建了一个 uniqueidentifier
而不是 nvarchar(450)
的 ID 字段
我认为 uniqueidentifier
的数据库性能主键和外键会比 nvarchar(450)
更好
有没有办法使用唯一键 Guid
而不是 string
和 uniqueidentifier
而不是 nvarchar(450)
和 ASP.NET Identity 3
?
有一个 如何将字符串转换为 Guid,但我希望数据库 table Id 成为一个 Guid。
我发现另一个 以及以前的 BETA 长度为 nvarchar(128)。给出的原因是并非所有数据库都支持 Guid,并且为了灵活性而对其进行了更改。
是否必须有一种简单的方法来从字符串更改为 Guid 而无需重写整个 identity 3
?
nvarchar(450)
实在是矫枉过正,在创建 SQL 服务器数据库约束时会发出各种警告。数据库管理员肯定不会喜欢这些警告。
ApplicationUser 继承自 IdentityUser base class,它被定义为具有一个字符串作为 id。所以要真正使用 guid/uniqueidentifier 你不需要从那个基础继承 class.
请注意,它在内部使用 guid 字符串作为 ID。您至少应该能够限制密钥的字段大小,如下所示:
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();
});
}
}
可以使用 Guids/uniqueidentifier 作为密钥,但这将需要更多的工作,除了使用您自己的基础 class(或者根本不使用基础 class ) 并使用自定义 DbContext 来映射模型。借用和修改 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 用字符串定义 FindById 方法签名。因此,重写您需要在需要通过 id 获取或查找的方法中将字符串转换为 guid。
我在我的 cloudscribe project 中正是这样做的,它有一个自定义的多租户身份实现
编辑:仔细观察代码,IdentityUser 有一个通用版本,您可以在其中定义密钥的类型
public class IdentityUser<TKey> where TKey : IEquatable<TKey>
所以您可以像
一样定义自己的基础class
IdentityUser<Guid>
但我仍然认为您需要覆盖采用 id 字符串并将该字符串转换为 guid 的 UserStore 方法。
我还没有弄乱这个例子的迁移(他们可能需要一些调整),但是 ASP.NET Identity v3 在这方面比 v2 更具可扩展性。
下面应该为您提供基于用户和角色的 Guid 主键的身份存储:
public class ApplicationUser : IdentityUser<Guid>
{
}
public class GuidDataContext :
IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
{
}
并在您的启动中 class:
services.AddIdentity<ApplicationUser, IdentityRole<Guid>>(
identity =>
{
// whatever identity options you want
identity.User.RequireUniqueEmail = true;
identity.Password.RequiredLength = 8;
}).
AddEntityFrameworkStores<GuidDataContext, Guid>().AddDefaultTokenProviders();
同样,如果您不需要向身份用户添加任何自定义字段,或自定义您的选项,您可以执行以下操作:
public class GuidDataContext :
IdentityDbContext<IdentityUser<Guid>, IdentityRole<Guid>, Guid>
{
}
并在您的启动中:
services
.AddIdentity<IdentityUser<Guid>, IdentityRole<Guid>>()
.AddEntityFrameworkStores<GuidDataContext, Guid>()
.AddDefaultTokenProviders();
您需要自定义 ApplicationUser
继承自 IdentityUser<TKey>
和自定义角色继承自 IdentityRole<TKey>
public class ApplicationUser : IdentityUser<Guid> { }
public class Role : IdentityRole<Guid> { }
自定义上下文 class 继承自 IdentityDbContext<ApplicationUser, Role, TKey>
并使用 fluent api 自动生成 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()");
});
}
}
然后在 Startup 中像这样向容器中添加身份服务
services.AddIdentity<ApplicationUser, Role>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders()
.AddUserStore<UserStore<ApplicationUser, Role, ApplicationDbContext, Guid>> ()
.AddRoleStore<RoleStore<Role, ApplicationDbContext, Guid>>();
如果您尚未创建数据库,请清除迁移文件夹和运行 ef 命令
当我查看 ASP.NET 3 Identity 时,它使用 string
而不是 Guid
作为唯一主键。
在我的 Entity Framework
code first
用户的 ApplicationUser
class 我继承了身份 class
public class ApplicationUser : IdentityUser
{
}
这导致当我创建我的 Entity Framework 迁移时,一个 table aspnetusers
被创建时使用的密钥类型是 nvarchar(450)
而不是 uniqueidentifier
当我将其与 ASP.NET Identity 2
ENtity Framework
项目进行比较时,它创建了一个 uniqueidentifier
而不是 nvarchar(450)
我认为 uniqueidentifier
的数据库性能主键和外键会比 nvarchar(450)
有没有办法使用唯一键 Guid
而不是 string
和 uniqueidentifier
而不是 nvarchar(450)
和 ASP.NET Identity 3
?
有一个
我发现另一个
是否必须有一种简单的方法来从字符串更改为 Guid 而无需重写整个 identity 3
?
nvarchar(450)
实在是矫枉过正,在创建 SQL 服务器数据库约束时会发出各种警告。数据库管理员肯定不会喜欢这些警告。
ApplicationUser 继承自 IdentityUser base class,它被定义为具有一个字符串作为 id。所以要真正使用 guid/uniqueidentifier 你不需要从那个基础继承 class.
请注意,它在内部使用 guid 字符串作为 ID。您至少应该能够限制密钥的字段大小,如下所示:
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();
});
}
}
可以使用 Guids/uniqueidentifier 作为密钥,但这将需要更多的工作,除了使用您自己的基础 class(或者根本不使用基础 class ) 并使用自定义 DbContext 来映射模型。借用和修改 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 用字符串定义 FindById 方法签名。因此,重写您需要在需要通过 id 获取或查找的方法中将字符串转换为 guid。
我在我的 cloudscribe project 中正是这样做的,它有一个自定义的多租户身份实现
编辑:仔细观察代码,IdentityUser 有一个通用版本,您可以在其中定义密钥的类型
public class IdentityUser<TKey> where TKey : IEquatable<TKey>
所以您可以像
一样定义自己的基础classIdentityUser<Guid>
但我仍然认为您需要覆盖采用 id 字符串并将该字符串转换为 guid 的 UserStore 方法。
我还没有弄乱这个例子的迁移(他们可能需要一些调整),但是 ASP.NET Identity v3 在这方面比 v2 更具可扩展性。
下面应该为您提供基于用户和角色的 Guid 主键的身份存储:
public class ApplicationUser : IdentityUser<Guid>
{
}
public class GuidDataContext :
IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
{
}
并在您的启动中 class:
services.AddIdentity<ApplicationUser, IdentityRole<Guid>>(
identity =>
{
// whatever identity options you want
identity.User.RequireUniqueEmail = true;
identity.Password.RequiredLength = 8;
}).
AddEntityFrameworkStores<GuidDataContext, Guid>().AddDefaultTokenProviders();
同样,如果您不需要向身份用户添加任何自定义字段,或自定义您的选项,您可以执行以下操作:
public class GuidDataContext :
IdentityDbContext<IdentityUser<Guid>, IdentityRole<Guid>, Guid>
{
}
并在您的启动中:
services
.AddIdentity<IdentityUser<Guid>, IdentityRole<Guid>>()
.AddEntityFrameworkStores<GuidDataContext, Guid>()
.AddDefaultTokenProviders();
您需要自定义 ApplicationUser
继承自 IdentityUser<TKey>
和自定义角色继承自 IdentityRole<TKey>
public class ApplicationUser : IdentityUser<Guid> { }
public class Role : IdentityRole<Guid> { }
自定义上下文 class 继承自 IdentityDbContext<ApplicationUser, Role, TKey>
并使用 fluent api 自动生成 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()");
});
}
}
然后在 Startup 中像这样向容器中添加身份服务
services.AddIdentity<ApplicationUser, Role>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders()
.AddUserStore<UserStore<ApplicationUser, Role, ApplicationDbContext, Guid>> ()
.AddRoleStore<RoleStore<Role, ApplicationDbContext, Guid>>();
如果您尚未创建数据库,请清除迁移文件夹和运行 ef 命令