EF Core Include() 语句对于 IQueryable 为 null

EF Core Include() statement is null for IQueryable

好的,如果没有大量代码支持,这可能有点难以解释,但我会尽力而为。

基本上我正在做一个涉及一对多关系的查询(目前在 ef core 2.1 上)。但是,"many" 集合在具体化时为空。

这是有问题的查询(为简洁起见删除了一些代码)

IQueryable<AccountViewModel> baseQuery = from ms in _managedSupportRepository.GetAllIncluding(m => m.Users) // here is the problem
                                          // a few lines of filters like the one below
                                          where string.IsNullOrEmpty(clientVersionFilter) || !string.IsNullOrEmpty(ms.ClientVersion) && ms.ClientVersion.Contains(clientVersionFilter, StringComparison.OrdinalIgnoreCase)
                                          join c in _contractRepository.GetAll() on ms.Id equals c.AssetId into contracts
                                          from c in contracts.DefaultIfEmpty()
                                          let isAssigned = c != null
                                          where !isAssignedFilter.valueExists || isAssignedFilter.value == isAssigned
                                          join a in _autotaskAccountRepository.GetAll() on ms.TenantId equals a.Id
                                          where string.IsNullOrEmpty(accountNameFilter) || !string.IsNullOrEmpty(a.AccountName) && a.AccountName.Contains(accountNameFilter, StringComparison.OrdinalIgnoreCase)
                                          select new AccountViewModel
                                          {
                                              AccountName = a.AccountName,
                                              ActiveUsers = ms.GetConsumed(), // here is the problem
                                              ClientVersion = ms.ClientVersion,
                                              ExternalIpAddress = ms.IpAddress,
                                              Hostname = ms.Hostname,
                                              Id = ms.Id,
                                              IsActive = ms.IsActive,
                                              IsAssigned = isAssigned,
                                              LastSeen = ms.CheckInTime,
                                              Status = ms.Status
                                          };

int count = baseQuery.Count();

baseQuery = baseQuery.Paging(sortOrder, start, length);

return (baseQuery.ToList(), count);

为清楚起见,_managedSupportRepository.GetAllIncluding(m => m.Users) 方法只是 .Include() 方法的包装器。

所以问题出在活跃用户的视图模型中 ActiveUsers = ms.GetConsumed(),GetConsumed()方法如下

public long GetConsumed()
{
    return Users.Count(u => !u.IsDeleted && u.Enabled && u.UserType == UserType.Active);
}

但是,这将引发空引用异常,因为 Users 集合为空。 现在我的问题是,当我明确要求加载用户集合时,为什么它为空? 目前的解决方法是将查询的第一行更改为 _managedSupportRepository.GetAllIncluding(m => m.Users).AsEnumerable() 这很荒谬,因为它会返回所有记录(几千条),因此性能不存在。

它需要是 IQueryable 的原因是可以应用分页,从而减少从数据库中提取的信息量。

感谢任何帮助。

这个问题有两个部分:

1) 不包含在投影中不包含

当您在提供程序上对 EF 进行查询时(服务器评估),您不会执行您的 new 表达式,因此:

ActiveUsers = ms.GetConsumed(),

从未真正执行过 ms.GetConsumed()。您为 new 传递的表达式被解析,然后 t运行 指定为查询(SQL 在 sql 服务器的情况下),但是 ms.GetConsumed() 是未在提供者上执行(在对数据库的查询上)。

因此您需要在 表达式 中包含 Users。例如:

select new AccountViewModel
{
    AccountName = a.AccountName,
    AllUsers = Users.ToList(),
    ActiveUsers = ms.GetConsumed(),
    // etc.
}

这样 EF 就知道查询需要 Users 并实际包含它(您没有在表达式中使用 Users,因此 EF 认为它不需要它,即使您 Include() 它...它可能会在 Visual Studio 中的 Output window 上显示警告,否则它会尝试仅投影和请求它从 new 表达式(不包括 Users)。

所以你需要在这里明确...尝试:

ActiveUsers = Users.Count(u => !u.IsDeleted && u.Enabled && u.UserType == UserType.Active);

Users将实际包含在内。

2) 当查询无法得到 t运行slated

时自动进行客户端评估

在这种情况下,Users 将被包括在内,因为它在实际表达式中...但是,EF 仍然不知道如何 t运行slate ms.GetConsumed() 到提供程序查询,所以它会工作(因为 Users 将被加载),但它不会在数据库上 运行,它仍然是运行 在内存上(它将进行客户端投影)。同样,如果您在 运行 那里 运行,您应该会在 Visual Studio 的 Output window 中看到关于此的警告。

EF Core 允许这样做(EF6 不允许),但您可以将其配置为在发生这种情况时抛出错误(在内存中评估的查询):

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        /* etc. */
        .ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
}

您可以在此处阅读更多相关信息:https://docs.microsoft.com/en-us/ef/core/querying/client-eval