Modello di messaggio chat:
public class ChatMessage
{
[Key] public long Id { get; set; }
[Required] public string Content { get; set; }
[Required] public DateTime TimePosted { get; set; }
public string AuthorId { get; set; }
[Required, ForeignKey("authorId")] public ApplicationUser Author { get; set; }
}
Ora voglio ottenere un elenco di messaggi chat da un determinato giorno, pur sapendo se il loro autore è nel ruolo "Voce":
var messages = await dbContext.ChatMessages.AsNoTracking()
.Where(chm => chm.TimePosted.Date == someDateTime.Date).OrderBy(chm => chm.TimePosted)
.ToListAsync();
var result = new List<Tuple<ChatMessage, bool>> { };
foreach(var m in messages)
result.Add(Tuple.Create(m, await userManager.IsInRoleAsync(Author, "Voice")));
Per quanto posso dire questo invierà al database tutte le query quante sono i messaggi di chat da recuperare , il che sembra antipatico, perché dovrebbe essere fatto in una sola query, non è vero? O almeno, un numero costante di domande, ma non lineare.
Sto sbagliando? Se sì, come dovrei farlo?
L'approccio corretto sembra venire dal commento di @Kirk Larkin, che sto convertendo in una risposta perché è più visibile di un commento e perché i commenti possono andare via in qualsiasi momento.
Ha collegato questa pagina di documenti: Migrazione dell'autenticazione e identità a ASP.NET Core 2.0 # Aggiungi le proprietà di navigazione POCO di IdentityUser , che dice:
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: C #
/// <summary> /// Navigation property for the roles this user belongs to. /// </summary> public virtual ICollection<IdentityUserRole<int>> Roles { get; } = new List<IdentityUserRole<int>>(); /// <summary> /// Navigation property for the claims this user possesses. /// </summary> public virtual ICollection<IdentityUserClaim<int>> Claims { get; } = new List<IdentityUserClaim<int>>(); /// <summary> /// Navigation property for this users login accounts. /// </summary> public virtual ICollection<IdentityUserLogin<int>> Logins { get; } = new List<IdentityUserLogin<int>>();
Per evitare duplicate di chiavi esterne durante l'esecuzione di EF Core Migrations, aggiungere quanto segue al metodo OnModelCreating della classe IdentityDbContext (dopo la base.OnModelCreating (); call): C #
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // Customize the ASP.NET Core Identity model and override the defaults if needed. // For example, you can rename the ASP.NET Core Identity table names and more. // Add your customizations after calling base.OnModelCreating(builder); builder.Entity<ApplicationUser>() .HasMany(e => e.Claims) .WithOne() .HasForeignKey(e => e.UserId) .IsRequired() .OnDelete(DeleteBehavior.Cascade); builder.Entity<ApplicationUser>() .HasMany(e => e.Logins) .WithOne() .HasForeignKey(e => e.UserId) .IsRequired() .OnDelete(DeleteBehavior.Cascade); builder.Entity<ApplicationUser>() .HasMany(e => e.Roles) .WithOne() .HasForeignKey(e => e.UserId) .IsRequired() .OnDelete(DeleteBehavior.Cascade); }
Una volta che questi passaggi sono stati fatti, credo che scrivere la query corretta dovrebbe diventare banale come una singola istruzione Include
. Codice del cervello compilato di seguito:
var usersAndRoles = await dbContext.ChatMessages.AsNoTracking()
.Include(msg => msg.Author).ThenInclude(author => author.Roles)
.Select(msg => new { Message = msg, IsVoice = msg.Author.Roles.Contains("Voice") })
.ToListAsync();