Basically Include
and ThenInclude
only role is to tell EF to load those nested objects while asking for data from the database. It doesn't allow You just to ommit the fact that the ArticleTag
is a list of objects and You need to use one of avaliable methods of such object. So in this case You want to apply Find
to the ArticleTag
list.
Edit:
See the complete example below. Note that by instructing EF about relationships between models it is not needed for me to even bother about including data (lat example).
Model creation:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Article>().HasData(
new Article { Id = 1, Summary = "Article summary 1", Title = "Article title 1" },
new Article { Id = 2, Summary = "Article summary 2", Title = "Article title 2" },
new Article { Id = 3, Summary = "Article summary 3", Title = "Article title 3" },
new Article { Id = 4, Summary = "Article summary 4", Title = "Article title 4" },
new Article { Id = 5, Summary = "Article summary 5", Title = "Article title 5" },
new Article { Id = 6, Summary = "Article summary 6", Title = "Article title 6" });
modelBuilder.Entity<Article>().HasKey(a => a.Id);
modelBuilder.Entity<Article>().HasMany(a => a.ArticleTags).WithOne(at => at.Article);
modelBuilder.Entity<Tag>().HasData(
new Tag { Id = 1, TagValue = "Tag 1" },
new Tag { Id = 2, TagValue = "Tag 2" });
modelBuilder.Entity<Tag>().HasKey(t => t.Id);
modelBuilder.Entity<Tag>().HasMany(t => t.ArticleTags).WithOne(at => at.Tag);
modelBuilder.Entity<ArticleTag>().HasData(
new ArticleTag { ArticleId = 1, TagId = 1 },
new ArticleTag { ArticleId = 2, TagId = 1 },
new ArticleTag { ArticleId = 1, TagId = 2 },
new ArticleTag { ArticleId = 2, TagId = 2 },
new ArticleTag { ArticleId = 3, TagId = 1 },
new ArticleTag { ArticleId = 4, TagId = 2 });
modelBuilder.Entity<ArticleTag>().HasKey(at => new { at.ArticleId, at.TagId });
modelBuilder.Entity<ArticleTag>().HasOne(at => at.Article).WithMany(a => a.ArticleTags);
modelBuilder.Entity<ArticleTag>().HasOne(at => at.Tag).WithMany(t => t.ArticleTags);
// Tag 1: Article 1,2,3
// Tag 2: Article 1,2,4
base.OnModelCreating(modelBuilder);
}
Controller:
public async Task<IActionResult> Index()
{
db.Database.EnsureCreated();
var articles = db.Articles.Include(at => at.ArticleTags)
.ThenInclude(t => t.Tag);
var articlesTag1 = articles.Where(a => a.ArticleTags.Any(at => at.Tag.TagValue == "Tag 1")).ToList();
var articlesTag2 = articles.Where(a => a.ArticleTags.Any(at => at.Tag.TagValue == "Tag 2")).ToList();
var articles1 = await db.ArticleTags.Include(at => at.Article)
.Include(at => at.Tag)
.Where(at => at.Tag.TagValue == "Tag 1").ToListAsync();
var articles2 = await db.ArticleTags
.Where(at => at.Tag.TagValue == "Tag 2").ToListAsync();
return View();
}
As You can see You can make it far easier by starting from the middle table, not needed for including chain thst will drill for data.