我在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
但是,品牌非常重要,因为它使某些属性脱离了客户模型。重组此查询的正确方法是什么,以便获得所需的结果(例如,具有相关品牌的客户,受UserCustomerAffiliation表上附属的userId的限制)。
在从客户(而不是UserCustomerAffiliation)“开始”查询之前,我已经看到了一个建议,但是从数据库优化的角度来看,这似乎与我的每一种直觉都是相反的(并且客户没有返回到UserCustomerAffiliation atm的导航属性)
答案 0 :(得分:0)
(经过一些研究)为什么会发生这种情况的答案非常有趣,并且是一个很好的例子,说明了为什么知道EF Core的工作方式对使用它很重要。
Linq通常会考虑推迟执行的想法。简而言之,如果我在特定的行上执行Linq语句,则在“需要”数据之前,它可能不会得到评估或执行。大多数情况下,我们使用.ToList()对此进行快捷操作,以强制立即执行。这里的总体思路是有时不需要数据集(例如,如果异常在求值之前发生,但在“加载”之后发生)。
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优化器丢弃了我需要的表。
此方法起作用的原因:
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');
但是,这种情况已经优化了。