Non riesco a capire come appiattire una collezione da molti a molti. Le entità sono per le tabelle Identity create con Entity Framework Core. Contengono le proprietà di navigazione che ho aggiunto manualmente perché le entità Identity non le includono per impostazione predefinita (insieme al codice del builder del modello personalizzato non mostrato)
public class AppUser : IdentityUser<long> {
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual List<AppUserRole> UserRoles { get; set; } = new List<AppUserRole>();
}
public class AppRole : IdentityRole<long> {
public virtual List<AppUserRole> UserRoles { get; set; } = new List<AppUserRole>();
}
public class AppUserRole : IdentityUserRole<long> {
public virtual AppUser User { get; set; }
public virtual AppRole Role { get; set; }
}
Questa è la chiamata nel mio repo:
public async Task<IEnumerable<AppUser>> GetAllWithRoles()
{
return await _dbSet
.AsNoTracking()
.Include(u => u.UserRoles)
.ThenInclude(ur => ur.Role)
.ToListAsync();
}
La chiamata sopra restituisce questa struttura:
[
{
"firstName": "XXXX",
"lastName": "YYYYY",
"userRoles": [
{
"role": {
"userRoles": [],
"id": 1,
"name": "xxx",
"normalizedName": "xxxx",
"concurrencyStamp": "1617fe40-77e2-46cb-9c1c-df597d09775c"
},
"userId": 1,
"roleId": 1
}
]
}
]
quello che voglio è questo:
[
{
"firstName": "Alex",
"lastName": "Florin",
"RoleName": "Role1",
},
{
"firstName": "Alex",
"lastName": "Florin",
"RoleName": "Role2",
},
{
"firstName": "Jon",
"lastName": "Smith",
"RoleName": "Role1",
},
]
Quello che voglio è appiattire la collezione. Ho cercato su SelectMany ma non riesco a capire come usarlo con una collezione da molti a molti visto che sono abbastanza nuovo per Linq. E so che il tipo di funzione della chiamata deve essere cambiato in un modello di visualizzazione che corrisponde alla mia struttura desiderata.
Automapper è un'altra opzione mentre sto usando questo per creare i viewmodels per le mie entità più semplici ma non sono chiaro come impostare l'uso per appiattire una relazione molti-a-molti
L'avevo capito. L'unico problema è che esclude qualsiasi utente con UserRoles = null ma dal momento che tutti gli utenti sono garantiti per avere almeno un ruolo nel nostro sistema, dovrebbe andare bene.
public async Task<IEnumerable<UserEditorViewModel>> GetAllWithRoles() {
return await _dbSet
.AsNoTracking()
.SelectMany(u => u.UserRoles)
.Select(ur => new UserEditorViewModel {
FirstName = ur.User.FirstName,
LastName = ur.User.LastName,
RoleName = ur.Role.Name
})
.ToListAsync();
}
Non sei sicuro di cosa vuoi appiattire esattamente, per selezionare tutti i ruoli da utente
users.Select(p => p.UserRoles.Role)
Per selezionare tutti gli utenti dal ruolo
roles.Select(p => p.UserRoles.User)
Modificare:
Penso che questo exmaple ti aiuterà https://blog.oneunicorn.com/2017/09/25/many-to-many-relationships-in-ef-core-2-0-part-2-hiding-as-ienumerable /
Il tuo modello potrebbe assomigliare a questo
public class AppUser : IdentityUser<long> {
public string FirstName { get; set; }
public string LastName { get; set; }
private ICollection<AppRole> UserRoles{ get; } = new List<PostTag>();
[NotMapped]
public IEnumerable<string> RoleNames => UserRole.Role.Name
}
public class AppRole : IdentityRole<long> {
private ICollection<AppRole> UserRoles{ get; } = new List<PostTag>();
[NotMapped]
public IEnumerable<AppRole> Users => UserRole.User
}
public class AppUserRole : IdentityUserRole<long> {
public long UserID{ get; set; }
public AppUser User { get; set; }
public long RoleID { get; set; }
public Role Role { get; set; }
}