实体框架7中的多对多查询

Whe*_*der 5 c# entity-framework entity-framework-core

我正在关注这个我从http://ef.readthedocs.org/en/latest/modeling/relationships.html获得的例子.

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; }
}
Run Code Online (Sandbox Code Playgroud)

现在我的问题是如何构建我的查询以获得TagId的帖子?就像是:

public List<Post> GetPostsByTagId(int tagId)
{
    //linq query here
}
Run Code Online (Sandbox Code Playgroud)

请记住这是EF7.

oct*_*ccl 10

我的第一个建议是改变你的收藏属性ICollection<T>而不是List<T>.你可以在这篇文章中找到一个非常好的解释.

现在回到你真正的问题,我会这样做你的查询:

public List<Post> GetPostsByTadId(int tagId)
{
    using(var context=new MyContext())
    {
      return context.PostTags.Include(p=>p.Post)
                             .Where(pt=> pt.TagId == tagId)
                             .Select(pt=>pt.Post)
                             .ToList();
    }
}
Run Code Online (Sandbox Code Playgroud)

你需要贪婪加载Post导航属性,因为EF7不支持延迟加载,还有如@Igor在他的解决方案建议,你应该包括PostTags作为一个DbSet在你的背景:

 public DbSet<PostTags> PostTags { get; set; }
Run Code Online (Sandbox Code Playgroud)

说明:

您的查询从PostTags表开始,因为在该表中您可以找到与特定标记相关的所有帖子.看到IncludePost桌子的内部联接.如果在两者之间应用连接PostTagsPosts过滤TagId,则将获得所需的列.通过Select电话,您告诉您只需要Post表格中的列.

如果您删除了Include呼叫,它仍然可以工作.由于Include你明确告诉你需要进行连接,但是使用它Select,EF的Linq提供者足够聪明,可以看到它需要隐式地进行连接以获得Posts列作为结果.