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(); 
相關問題