Reputation: 36026
In Entity Framework Core one can setup a many-to-many relationship via a join table.
I don't know how to query a relationship like this in an efficient way. Given the reference relationships below, I have, a Post
entity and the PostTags
collection is null. I want to load all the Tag
s associated with the Post
and the best I have so far is something that looks like this:
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();
}
}
I really would prefer to return an ICollection<Tag>
via a single query to the DB.
This is the reference implementation from 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; }
}
Upvotes: 1
Views: 558
Reputation: 205589
If all you need is to get a list of the tags associated with a post, you can use simple projection query. Just make sure to start with a DbSet<>
(i.e. EF Core IQueryable<>
) rather than materialized object / collection, e.g.
ICollection<Tag> GetAllTags(Post somePost)
{
return await dbContext.Set<PostTag>()
.Where(pt => pt.PostId == somePost.PostId)
.Select(pt => pt.Tag)
.ToListAsync();
}
If you indeed want to load them into the passed Post
entity instance, you can use a combination of explicit and eager loading via Query
method:
void LoadAllTags(Post somePost)
{
await dbContext.Entry(somePost)
.Collection(p => p.PostTags)
.Query()
.Include(pt => pt.Tag)
.LoadAsync();
}
Upvotes: 3