我有一个POCO Domain Entity类,其中包含导航到相关记录的便捷方法.我正在使用AdventureWorks2008R2数据库来演示我正在尝试完成的任务.所有这些查询都可以在LINQPad中运行,以观察生成的SQL语句.
SalesOrderHeaders.Where(s => s.SalesOrderID == 43659)
.Single().SalesOrderDetails
该语句产生2个SQL语句.一个用于SalesOrderHeader记录,另一个用于检索SalesOrderDetails.现在考虑这个导航到另一个相关表的语句:
SalesOrderHeaders.Where(s => s.SalesOrderID == 43659)
.Single().SalesOrderDetails.Select(s => s.SpecialOfferProduct)
检索单个SalesOrderHeader记录后,域类将包含这样的便利属性:
public IQueryable<SpecialOfferProduct> SpecialProducts
{
get
{
return SalesOrderDetails.Where(sod => sod.OrderQty > 3)
.Select(s => s.SpecialOfferProduct)
.AsQueryable();
}
}
该语句产生多个SELECT语句:一个用于SpecialOfferProduct中的每个记录.我的问题是:为什么导航属性不会产生单个SELECT语句?这是一个巨大的性能问题,因为它会产生很多不必要的喋喋不休.我可以使用LINQ SQL语法,但这只是在使用存储库创建原始查询时.在这种情况下,我有一个SalesOrderHeader对象的实例,并且无法访问类中的Context或Repository.有没有办法强制它使用JOIN创建一个SELECT语句?
如果没有办法,我想在我的存储库中创建一个额外的方法来填充这些属性.问题是我有两个步骤:1检索SalesOrderHeader对象,然后使用适当的LINQ语句填充其他属性,这将强制JOIN语法.
最佳答案 如评论中所述,您需要
Include
方法:
SalesOrderHeaders.Include(s => s.SalesOrderDetails
.Select(d => d.SpecialOfferProduct))
.Where(s => s.SalesOrderID == 43659)
.Single().SalesOrderDetails
这将加入所需的数据(在SQL中)并填充导航属性.
但请注意,您不能使用类似的语法
.Include(s => s.SalesOrderDetails.Where(sod => sod.OrderQty > 3)
.Select(d => d.SpecialOfferProduct))
这似乎会部分填充SalesOrderDetails. EF团队有变更请求来实现这一点,但到目前为止,还没有完成.
另一方面注意,将SpecialProducts作为IQueryable返回是没用的,因为集合上的后续查询无论如何都不会被转换为SQL.您只能在内存语句中访问该属性,而不是在linq-to-enitites查询中(EF无法将该属性转换为SQL).