EF 6.x 代码优先:不同 SQL 为导航生成 属性

EF 6.x Code First: Different SQL Generated for Navigation Property

我是一名经验丰富的 Web 开发人员,拥有丰富的 T-SQL 和架构设计经验,但对 EF 还很陌生(直接跳到 EF 6!)。我想知道我的 POCO 有什么问题,我为以下两个查询生成了不同的 SQL。

基本上,我有两个对象,“Parent”和“ChildThing”,具有一对多导航 属性。这是“父”(自然键,未生成):

Public Class Parent
    <Key>
    <DatabaseGenerated(DatabaseGeneratedOption.None)> <MaxLength(10), MinLength(4)>
    Public Property ParentCode As String

    Public Property Description As String

    ' '''navigation property
    Public Overridable Property ChildThings As ICollection(Of ChildThing) = New HashSet(Of ChildThing)

End Class

这是我的“ChildThing”

Public Class ChildThing
    <Key, ForeignKey("Parent"), Column(Order:=10), DatabaseGenerated(DatabaseGeneratedOption.None), MaxLength(10), MinLength(4)>
    Public Property ParentParentCode As String

    <Key, Column(Order:=20), DatabaseGenerated(DatabaseGeneratedOption.None)>
    Public Property DateEffective As Date

    Public Property Price As Decimal
 
    ' '''Navigation Property: The 'parent' record associated with child 
    Public Overridable Property Parent As Parent
End Class

因此,如果我使用父级导航 属性 + WHERE 编写查询,如下所示:

    Dim effectiveDate As Date = DateTime.Parse("1/1/2015").Date

    Dim parentObj = db.Parents().Find("7001")

    Dim filteredPrices = From x In parentObj.ChildThings
                         Where x.DateEffective = effectiveDate

我得到 sql for filteredPrices 似乎忽略了 WHERE.. 我的意思是,它 一个 WHERE,但它只考虑了POCO 模型中定义的 FK:

SELECT 
    [Extent1].[ParentParentCode] AS [ParentParentCode], 
    [Extent1].[DateEffective] AS [DateEffective], 
    [Extent1].[Price] AS [Price]
    FROM [dbo].[ChildThings] AS [Extent1]
    WHERE [Extent1].[ParentParentCode] = @EntityKeyValue1

如果我直接针对 ChildThings 构建查询,

    Dim filteredPrices = From x In db.ChildThings
              Where x.ParentParentCode = "7001" AndAlso x.DateEffective = effectiveDate

然后,WHERE 中包含两个参数..

SELECT 
    [Extent1].[ParentParentCode] AS [ParentParentCode], 
    [Extent1].[DateEffective] AS [DateEffective], 
    [Extent1].[Price] AS [Price]
    FROM [dbo].[ChildThings] AS [Extent1]
    WHERE (N'7001' = [Extent1].[ParentParentCode]) AND ([Extent1].[DateEffective] = @p__linq__0)

解决方案

感谢@MattBrooks 结束了我疲惫的 google 搜索。使用他提供的 MSDN link 我能够得到以下解决方案( 我不得不关闭此导航集合的延迟加载 属性

    Dim parentObj = db.Parents().Find("7001")

    db.Entry(parentObj) _
        .Collection(Function(x) x.ChildThings) _
        .Query() _
        .Where(Function(x) x.DateEffective = effectiveDate) _
        .Load() 'extension meth. from System.Data.Entity

我一直在使用 LINQ,只是使用内存中的对象.. 以前从未 w/EF。我从调试中知道 'expanding this node will process results' 或调用 .ToList 会导致集合为 'processed',并且我将这些概念投射到我关于 EF 如何执行查询的心智模型中。我仍然不是很清楚 EF 的所有魔力,但是,到达那里。

这是标准的 EF 行为。访问集合属性时,在为查询过滤结果之前,所有相关实体都会从数据库延迟加载到集合中。在这种情况下,实际过滤是由 LINQ-to-Objects 执行的,而不是您期望的 LINQ-to-Entities。

我发现这是过去有用的资源 — https://msdn.microsoft.com/en-gb/data/jj574232.aspx。它显示了一些通过集合 属性 有效查询相关实体的选项。