我在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();
当我应该能够做这样的事情来简化它(并删除本地评估的不必要的东西与db)
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非常重要,因为它驱动了一些客户模型的属性。重构此查询的正确方法是什么,以便获得我想要的结果(例如,客户及其相关品牌,受UserCustomerAffiliation表附属的userId限制)。
我之前看到过一个建议,即从客户“开始”查询而不是UserCustomerAffiliation,但这似乎与我从数据库优化角度看到的每一个本能相反(而且客户没有返回到UserCustomerAffiliation atm的导航属性)。
为什么会发生这种情况(经过一些研究后)的答案非常有趣,并且为什么了解EF Core如何工作对于使用它很重要。
Linq总体上研究延迟执行的想法。简单地说,如果我在特定行上创建Linq语句,则在“需要”数据之前可能无法对其进行评估或执行。大多数情况下,我们使用强制立即执行的.ToList()来快捷。这里的一般想法是,有时不需要数据集(例如,如果在评估之前发生异常,但在“加载”之后发生异常)。
EF Core更进一步,将延迟执行的想法与数据库优化联系起来。例如,如果我从数据库中获取数据的子集:
var result = _context.SomeTable.Where(x => x.name == "SomeValue");
但后来我关心的是数据集的大小:
return result.Count;
可以优化DB调用
select count(*) from SomeTable where name = "SomeValue";
代替
select * from SomeTable where name = "SomeValue";
同样,我上面的查询正在被优化掉。因为我在评估之前将整个事物链接起来,所以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();
是因为我强制执行类似的查询
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');
但是,这会得到优化。