14

当我查看ASP.NET 3 Identity时,它使用string而不是Guid作为唯一主键。如何使EF-Core使用Guid而不是字符串作为其ID /主键

在我Entity Frameworkcode first用户ApplicationUser I类继承Identity类

public class ApplicationUser : IdentityUser 
{ 
} 

导致当我创建我的实体框架迁移表aspnetusers得到与nvarchar(450)代替uniqueidentifier

一键式创建

当我把它与ASP.NET Identity 2ENtity Framework项目比较时,它创建了一个ID字段uniqueidentifier而不是nvarchar(450)

我会想象数据库性能主键和uniqueidentifier外键会比nvarchar(450)

更好是否有使用的唯一键Guid代替stringuniqueidentifier,而不是nvarchar(450)ASP.NET Identity 3的方法吗?

有一个previous question如何将字符串转换为Guid,但我希望数据库表Id是一个Guid。

我发现另一个question以及以前的BETA时,长度为nvarchar(128)。给出的理由是,并非所有的数据库都支持Guids,并且它的灵活性已经改变。

是否必须有一个简单的方法来从字符串更改为Guid而不用重写整个identity 3

nvarchar(450)确实有点矫枉过正,并在创建SQL Server数据库约束时给出各种警告。数据库管理员肯定不会像这些警告。

回答

30

您定制ApplicationUser继承IdentityUser<TKey>需要和自定义角色继承IdentityRole<TKey>

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

自定义上下文类从IdentityDbContext<ApplicationUser, Role, TKey>继承和使用流畅的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()"); 
     }); 
    } 
} 

然后启动添加标识服务于容器这样

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

如果您尚未创建数据库,清除迁移文件夹,运行EF命令

+0

请注意,有一个EntityFramework 7/EntiryFramework Core 1.0中的bug直到rc1-final,这会在使用外键的泛型时破坏迁移,而这些泛型不会通过内置类型(如Guid)关闭。这已在rc2-nightlies中解决了一段时间,但尚未发布。 https://github.com/aspnet/EntityFramework/issues/3545 – Tseng

2

ApplicationUser继承自IdentityUser基类,它被定义为具有一个字符串作为id。因此,要真正使用guid/uniqueidentifier,您将不需要从该基类继承。

请注意,它在内部使用的是用于id的guid字符串。你应该至少能限制的关键领域大小像所示:

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

     }); 

    } 
} 

它是可以使用的GUID /唯一标识符为关键,但将需要更多的工作,除了使用自己的基地类(或根本不使用基类)并使用自定义的DbContext来映射模型。借用和修改EF code from here应该让你走,你将不得不从UserStore继承并覆盖用于通过id查找用户的虚拟方法,因为接口IUserStore使用字符串定义FindById方法签名。因此,重写您需要将字符串转换为您需要获取或通过id查找的方法中的guid。

我做的正是我cloudscribe project具有身份

编辑自定义的多租户的实现:其实看代码越接近IdentityUser有一个通用版本,在那里你可以定义键的类型

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

所以,你可能可以只定义诸如

IdentityUser<Guid> 

自己的基类,但我仍然认为您需要重写使用id字符串的UserStore方法,并将字符串转换为guid。

9

我还没有搞错这个例子的迁移(他们可能需要一些调整),但ASP.NET身份v3比v2在这方面更具可扩展性。

下应该给你一个身份存储基于用户和角色一样的Guid主键:

public class ApplicationUser : IdentityUser<Guid> 
{ 
} 

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

,并在您启动类:

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(); 
相关问题