对EF Core中的多对多关系执行有效的查询

时间:2019-01-22 12:20:49

标签: .net entity-framework .net-core entity-framework-core

在Entity Framework Core中,可以通过联接表建立many-to-many关系。

我不知道如何以有效的方式查询这样的关系。给定下面的引用关系,我有一个Post实体,并且PostTags集合为空。我想加载与Tag相关的所有Post,到目前为止,我所拥有的最好的东西是这样的:

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();
    }
}

我真的希望通过单个查询将一个ICollection<Tag>返回到数据库。


这是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; }
}

1 个答案:

答案 0 :(得分:3)

如果只需要获取与帖子关联的标签列表,则可以使用简单的投影查询。只需确保以DbSet<>(即EF Core IQueryable<>)开头,而不是以物化对象/集合(例如

)开头
ICollection<Tag> GetAllTags(Post somePost)
{
    return await dbContext.Set<PostTag>()
        .Where(pt => pt.PostId == somePost.PostId)
        .Select(pt => pt.Tag)
        .ToListAsync();
}

如果您确实想将它们加载到传递的Post实体实例中,则可以通过Query方法使用显式加载和紧急加载的组合:

void LoadAllTags(Post somePost)
{
    await dbContext.Entry(somePost)
        .Collection(p => p.PostTags)
        .Query()
        .Include(pt => pt.Tag)
        .LoadAsync();
}