我有一个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语法。
答案 0 :(得分:2)
如评论中所述,您需要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)。