4

我有一个 POCO 域实体类,其中包含导航到相关记录的便捷方法。我正在使用 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 语法。

4

1 回答 1

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 团队有一些变更请求来实现这一点,但到目前为止,这还没有完成。

另一个注意事项是返回是没有用的SpecialProductsIQueryable因为集合上的后续查询无论如何都不会转换为 SQL。您首先只能在内存中的语句中访问该属性,而不是在 linq-to-enitites 查询中(EF 无法将该属性转换为 SQL)。

于 2013-08-24T11:27:10.700 回答