通过多个嵌套对象关系使用EF Core进行过滤

问题描述

我有一个新要求,即根据构成黑名单的内容过滤查询返回的报告。

因此,最初,我有这个查询,它带回了所有所需的相关信息,并获得了与该特定用户相关的报告的列表。

var reports = from r in Context.Reports
                          join ax in Context.AuthorizationXref on r.Id equals ax.ReportId
                          join g in Context.Groups on ax.GroupId equals g.Id
                          join ugx in Context.UsersGroupsXref on g.Id equals ugx.GroupId
                          where ugx.UserId == id
                          select r;

AuthorizationXref具有ReportID和GroupId。

public partial class AuthorizationXref
    {
        public int Id { get; set; }
        public int ReportId { get; set; }
        public int GroupId { get; set; }

        public virtual Groups Group { get; set; }
        public virtual Reports Report { get; set; }
    }

public partial class Groups
    {
        public Groups()
        {
            AuthorizationXref = new HashSet<AuthorizationXref>();
            UsersGroupsXref = new HashSet<UsersGroupsXref>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }

        public virtual ICollection<AuthorizationXref> AuthorizationXref { get; set; }
        public virtual ICollection<UsersGroupsXref> UsersGroupsXref { get; set; }
    }

用户多对多组多对多报表(多对多是通过XREF完成的。)

虽然在这里,我将它放在700ms的基准上,这似乎确实很慢,但我意识到我对数据库至少执行了4次命中,所以我尝试这样做或多或少地等于相同的数据,但快了约7倍:

    var repo = context.Reports
        .Include(x => x.AuthorizationXref)
        .ThenInclude(x => x.Group)
        .ThenInclude(x => x.UsersGroupsXref)
        .ToList();

这大约需要100ms的时间,但不会对userId进行任何过滤。这些基准测试是在开发环境中进行的,并且只会随着我们进入更高的环境而恶化,在更高的环境中,越来越多的报告被添加用户中。我知道使用Selects效率更高,但是我找不到在实体上嵌套复杂的多对多选择的示例。

我可以说到这里为止,但是不知道在哪里放置其他步骤以更深入地研究对象。

var asdf = repo.Where(x=>x.AuthorizationXref.Any(y=>y.ReportId==x.Id));

最终目标是我需要一个由userId组成的报告列表,以删除ID在另一个表上显示的那些报告。因此,有一个名为UserReportFilter的表,它具有ReportId和UserId,该表中的任何报告都不应出现在我的最终结果中。

作为一个旁注,如果有人可以将我指向关于如何使用表达式的教程(最好是不假定读者完全了解所有内容的教程)的方向,我将不胜感激。我碰到了this article,学习像这样的东西似乎是很有意义的事情,但是在解释中我将需要更多的知识。我理解这个概念,并使用基本的Func返回值进行查询,但没有什么涉及面很广。

解决方法

我假设您在Reports和UserReportFilter表之间具有联系,因为您在UserReportFilter表中具有ReportId。下面的表达式应该起作用,

var reports = context.Reports
    .Include(x => x.AuthorizationXref)
    .ThenInclude(x => x.Group)
    .ThenInclude(x => x.UsersGroupsXref)
    .Include(x => x.UserReportFilters)
    .Where(x => x.AuthorizationXref.Any(y => y.Group.UsersGroupsXref.Any(z => z.UserId==id))
    .ToList();