In Entity Framework Core è possibile impostare una relazione molti-a-molti tramite una tabella di join.
Non so come interrogare una relazione come questa in modo efficiente. Date le relazioni di riferimento di seguito, ho, un'entità Post
e la collezione PostTags
è nulla. Voglio caricare tutti i Tag
associati al Post
e il meglio che ho finora è qualcosa che assomiglia a questo:
void GetAllTags(Post somePost)
{
await dbContext.Entry(somePost)
.Collection(p => p.PostTags)
.LoadAsync();
foreach(var postTag in somePost.PostTags)
{
await dbContext.Entry(postTag)
.Reference(p => p.Tag)
.LoadAsync();
}
}
Preferirei davvero restituire un ICollection<Tag>
tramite una singola query al DB.
Questa è l'implementazione di riferimento da Relationships - EF Core | Microsoft Docs
class MyContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PostTag>()
.HasKey(t => new { t.PostId, t.TagId });
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId);
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId);
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
Se tutto ciò che serve è ottenere un elenco dei tag associati a un post, è possibile utilizzare una semplice query di proiezione. Assicurati di iniziare con un DbSet<>
(es. EF Core IQueryable<>
) anziché oggetto / collezione materializzato, ad es.
ICollection<Tag> GetAllTags(Post somePost)
{
return await dbContext.Set<PostTag>()
.Where(pt => pt.PostId == somePost.PostId)
.Select(pt => pt.Tag)
.ToListAsync();
}
Se in effetti vuoi caricarli nell'istanza dell'entità Post
passata, puoi utilizzare una combinazione di caricamento esplicito e impaziente tramite il metodo Query
:
void LoadAllTags(Post somePost)
{
await dbContext.Entry(somePost)
.Collection(p => p.PostTags)
.Query()
.Include(pt => pt.Tag)
.LoadAsync();
}