导航 属性 未评估 EF Core

Navigation Property Not Evaluated EF Core

我在 EF Core 中遇到问题,我试图获取相关实体及其所有依赖结构,但没有取得太大成功。

目前,我有这样的查询:

var user = new Guid(id);
var userCustAffs = _data.UserCustomerAffiliation.Include(x => x.Customer)
                     .ThenInclude(x => x.Brand).Where(x => x.UserId.Equals(user)).ToList();
var result =  userCustAffs.Select(p => p.Customer).ToList();

什么时候我应该能够做这样的事情来简化它(并删除在本地与数据库评估的不必要的东西)

var user = new Guid(id);
var userCustAffs = _data.UserCustomerAffiliation.Include(x => x.Customer)
                               .ThenInclude(x => x.Brand).Where(x => x.UserId.Equals(user))
                               .Select(y => y.Customer).ToList();

然而,当我执行后一个查询时,我得到一个错误

The Include operation for navigation '[x].Customer.Brand' is unnecessary and was ignored 
because the navigation is not reachable in the final query results

但是,Brand 非常重要,因为它将某些属性从 Customer 模型中剔除。重组此查询以便获得所需结果的正确方法是什么(例如,客户及其相关品牌,受 UserCustomerAffiliation table 附属的 userId 限制)。

我之前看过 "start" 来自客户而不是 UserCustomerAffiliation 的查询的建议,但这似乎违背了我从数据库优化的角度来看的所有直觉(并且客户没有导航 属性 回到 UserCustomerAffiliation atm)。

为什么会发生这种情况(经过一些研究)的答案非常有趣,并且很好地说明了为什么了解 EF Core 的工作原理对于使用它很重要。

Linq 通常采用延迟执行的思想。简而言之,如果我在特定行上创建 Linq 语句,它可能不会被评估或执行,直到数据为 "needed." 大多数情况下,我们使用强制立即执行的 .ToList() 来简化它。这里的一般想法是有时不需要数据集(例如,如果在评估之前发生异常但在评估之后将是 'loaded')。

EF Core 更进一步,将延迟执行的想法与数据库优化联系起来。例如,如果我从数据库中获取数据的子集:

var result = _context.SomeTable.Where(x => x.name == "SomeValue");

但后来我只关心数据集的大小:

return result.Count;

数据库调用可以优化为

select count(*) from SomeTable where name = "SomeValue"; 

而不是

select * from SomeTable where name = "SomeValue";

同样,我上面的查询正在被优化掉。因为我在评估之前链接了整个东西,EF Core 优化器丢弃了我需要的 table。

这样做的原因:

var user = new Guid(id);
var userCustAffs = _data.UserCustomerAffiliation.Include(x => x.Customer)
                                         .ThenInclude(x => x.Brand).Where(x => 
                                         x.UserId.Equals(user)).ToList();
var result =  userCustAffs.Select(p => p.Customer).ToList();

是因为我强制执行类似

的查询
Select u.*, c.*, b.* from usercustomeraffiliation u, 
        inner join Customer c  on u.customerid = c.id 
        inner join Brand b on c.brandid = c.id 
        where u.userid = 'userId';

然后剥离内存中的客户对象(以及其下的品牌对象)。能够生成如下查询会更有效率:

Select c.*, b.* from Customer c  on u.customerid = c.id 
        inner join Brand b on c.brandid = c.id 
        where c.id in (select u.customerid from usercustomeraffiliation u 
                              where u.userid = 'userId');

但是,这会被优化掉。