14

Quando guardo l'identità di ASP.NET 3 utilizza uno string e non un Guid per la chiave primaria univoca.Come rendere EF-Core utilizzare un Guid invece di String per l'ID/Chiave primaria

In ApplicationUser classe miei Entity Frameworkcode first Users' ho ereditare la classe di identità

public class ApplicationUser : IdentityUser 
{ 
} 

che si traduce in quando creo il mio Entity Framework migrazioni un tavolo aspnetusers sempre creato con un tipo di chiave di nvarchar(450) invece di uniqueidentifier

Quando si confronta questo progetto con ASP.NET Identity 2ENtity Framework è stato creato un campo ID di uniqueidentifier e non nvarchar(450)

mi immagino per le chiavi primarie prestazioni del database e chiavi esterne di uniqueidentifier sarebbe meglio che nvarchar(450)

C'è un modo per utilizzare per l'unica chiave Guid invece di string e uniqueidentifier invece di nvarchar(450) con ASP.NET Identity 3?

C'è un previous question come convertire una stringa in una guida ma voglio che l'ID della tabella del database sia una guida.

Ho trovato un altro question anche per un BETA precedente quando la lunghezza era nvarchar (128). Il motivo è che non tutti i database supportano Guids e sono stati modificati per la flessibilità.

È necessario un modo semplice per passare da stringa a guida senza riscrivere l'intero identity 3?

nvarchar(450) è davvero eccessivo e fornisce tutti i tipi di avvisi durante la creazione di vincoli di database di SQL Server. Gli amministratori del database non gradiranno definitivamente questi avvertimenti.

risposta

30

avete bisogno del ApplicationUser ereditare da IdentityUser<TKey> e ruolo personalizzato ereditano da IdentityRole<TKey>

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

classe contesto personalizzato ereditare da IdentityDbContext<ApplicationUser, Role, TKey> e utilizzare API fluente per auto generare chiavi 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()"); 
     }); 
    } 
} 

quindi in avvio aggiungere il servizio di identità per contenitore come questo

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

Se non si è creato il database, cancellare la cartella migrazioni ed eseguire comandi ef

+0

Si prega di notare, che v'è un bug in EntityFramework 7/EntiryFramework Core 1.0 fino a rc1-final, che interrompe le migrazioni quando si utilizzano i generici in chiavi esterne, che non vengono chiuse sui tipi predefiniti (come Guid). Questo problema è stato risolto in rc2-nightly per un po 'di tempo, ma non è ancora stato rilasciato. https://github.com/aspnet/EntityFramework/issues/3545 – Tseng

2

ApplicationUser eredita dalla classe base IdentityUser che è definita come avente una stringa come id. Quindi, per usare davvero un guid/uniqueidentifier, non avresti bisogno di ereditare da quella classe base.

Si noti che internamente sta utilizzando le string di guida per gli ID. Si dovrebbe almeno essere in grado di limitare le dimensioni del campo della chiave, come illustrato di seguito:

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

     }); 

    } 
} 

E 'possibile utilizzare GUID/uniqueidentifier per la chiave, ma che richiederà più lavoro, oltre a utilizzare la propria base class (o non utilizzare affatto una classe base) e utilizzare un DbContext personalizzato per mappare il modello. Prendere in prestito e modificare lo EF code from here dovrebbe farti andare, dovresti ereditare da UserStore e sovrascrivere i metodi virtuali per cercare un utente per id, perché l'interfaccia IUserStore definisce la firma del metodo FindById con una stringa. In questo modo è necessario convertire la stringa in un guid all'interno dei metodi in cui è necessario recuperare o trovare l'ID.

che sto facendo esattamente questo nel mio cloudscribe project, che dispone di un'implementazione personalizzata multi-tenant di Identità

EDIT: in realtà guardando più da vicino il codice del IdentityUser ha una versione generica in cui è possibile definire il tipo di chiave

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

Così si potrebbe essere in grado di definire solo la propria classe di base come

IdentityUser<Guid> 

ma io continuo a pensare sarà necessario sovrascrivere i metodi di UserStore che accettano una stringa di identificazione e convertono la stringa in un guid.

9

Non ho ancora incasinato le migrazioni per questo esempio (potrebbero essere necessarie alcune modifiche), tuttavia ASP.NET Identity v3 è molto più estensibile rispetto a v2 in questo senso.

Di seguito dovrebbe darvi un negozio di identità sulla base di Guid chiavi primarie per utenti e ruoli allo stesso modo:

public class ApplicationUser : IdentityUser<Guid> 
{ 
} 

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

e nella tua classe di avvio:

services.AddIdentity<ApplicationUser, IdentityRole<Guid>>(
      identity => 
      { 
       // whatever identity options you want 
       identity.User.RequireUniqueEmail = true; 
       identity.Password.RequiredLength = 8; 
      }). 
      AddEntityFrameworkStores<GuidDataContext, Guid>().AddDefaultTokenProviders(); 

Allo stesso modo, se non l'avete fatto è necessario aggiungere campi personalizzati all'identità utente o personalizzare le opzioni, è sufficiente effettuare le seguenti operazioni:

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

e nel vostro avvio:

services 
    .AddIdentity<IdentityUser<Guid>, IdentityRole<Guid>>() 
    .AddEntityFrameworkStores<GuidDataContext, Guid>() 
    .AddDefaultTokenProviders(); 
Problemi correlati