Sto configurando un nuovo progetto utilizzando EF Core 2 e ho bisogno di avere una proprietà di navigazione su IdentityUser, così quando richiedo un utente posso includere (x => x.Roles) e ottenere i ruoli in cui è l'utente.
Questo post su Github ha alcune idee, ma ho provato ognuna e tutti i problemi di causa, creando nuovi / duplicati campi nelle tabelle Identità o causando problemi con le migrazioni. E nessun commento ufficiale da parte di nessuno nel team EF.
https://github.com/aspnet/Identity/issues/1361
Mi stavo chiedendo se qualcuno ha questo funziona correttamente? E potrebbe condividere i loro mapping e modelli di DB EF.
Consultare la documentazione per "Migrazione dell'autenticazione e dell'identità in ASP.NET Core 2.0", in particolare la sezione " Aggiungi proprietà di navigazione POCO di IdentityUser ":
Le proprietà di navigazione Core di Entity Framework (EF) della base
IdentityUser
POCO (Plain Old CLR Object) sono state rimosse. Se il progetto 1.x ha utilizzato queste proprietà, aggiungerle manualmente al progetto 2.0:
/// <summary>
/// Navigation property for the roles this user belongs to.
/// </summary>
public virtual ICollection<IdentityUserRole<int>> Roles { get; } = new List<IdentityUserRole<int>>();
Per evitare duplicate di chiavi esterne durante l'esecuzione di EF Core Migrations, aggiungere quanto segue al metodo
OnModelCreating
classeIdentityDbContext
(dopo labase.OnModelCreating();
call):
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
builder.Entity<ApplicationUser>()
.HasMany(e => e.Roles)
.WithOne()
.HasForeignKey(e => e.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
}
Quanto sopra soddisferà solo il compito di accedere agli ID di ruolo tenuti contro un utente tramite la tabella di collegamento IdentityUserRole
. Per accedere all'entità di ruolo stessa tramite una proprietà di navigazione, è necessario aggiungere un'altra proprietà di navigazione (questa volta contro un'entità che eredita da IdentityUserRole
). Vedi i passaggi seguenti:
Roles
nell'entità IdentityUser
come segue: public virtual ICollection<UserRole> Roles { get; set; } = new List<UserRole>();
UserRole
cui sopra: public class UserRole : IdentityUserRole<int>
{
public virtual IdentityRole<int> Role { get; set; }
}
UserRole
come segue: builder.Entity<UserRole>()
.HasOne(e => e.Role)
.WithMany()
.HasForeignKey(e => e.RoleId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
User user = context.Set<User>()
.Include(u => u.Roles)
.ThenInclude(r => r.Role)
.FirstOrDefault();
Nota:
IdentityUserRole
sarà necessario migrare o ricreare il database. UserManager
o RoleManager
, sarà necessario utilizzare l'overload AddUserStore()
di AddUserStore()
e AddRoleStore
nella classe di avvio, ad es. services.AddIdentity<User, IdentityRole<int>>()
.AddUserStore<UserStore<User, IdentityRole<int>, SqlContext, int, IdentityUserClaim<int>, UserRole, IdentityUserLogin<int>, IdentityUserToken<int>, IdentityRoleClaim<int>>>()
.AddRoleStore<RoleStore<IdentityRole<int>, SqlContext, int, UserRole, IdentityRoleClaim<int>>>()
.AddDefaultTokenProviders();
Ottengo i ruoli per query personalizzata e potrebbe essere utile.
var roles = (from role in _dbContext.Roles
let userRoles = _dbContext.UserRoles.Where(ur => ur.UserId == user.Id).Select(ur => ur.RoleId)
where userRoles.Contains(role.Id)
select role
).ToList();