c# - 使用导航属性的 LINQ 查询生成多个 SELECT 语句

标签 c# sql linq entity-framework linq-to-entities

我有一个 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 语句?

如果没有办法做到这一点,我正在考虑在我的存储库中创建一个额外的方法来填充这些属性。问题是我有 2 个步骤: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)。

关于c# - 使用导航属性的 LINQ 查询生成多个 SELECT 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18414646/

相关文章:

sql - partition by/order by 是否暗示查询中的排序?

c# - 在 LINQ 查询中按时间顺序对分组查询进行排序

c# - Global.asax 中的 HttpApplication.Context null

sql - 具有递归层次结构的互连数据

c# - 以编程方式单击 dataGridView 标题单元格

mysql - 带有子查询的 SQL 查询

c# - Linq 选择列表中存在的对象(A,B,C)

c# - 如何在不加载整行的情况下更新 LINQ 中的单个列?

c# - WPF - Storyboard 完成事件

c# - 如何在 C# 中读取二进制文件直到 EOF