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

时间:2015-04-24 19:09:09

标签: entity-framework ef-code-first linq-to-entities poco

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

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

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

因此,如果我使用Parent的导航属性+ 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

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

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结束我令人筋疲力尽的谷歌搜索。使用他提供的MSDN链接我能够得到以下解决方案(我必须关闭此导航集合属性的延迟加载

    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,只使用内存中的对象..从未使用过EF。我从调试中知道“扩展此节点将处理结果”或调用.ToList会导致集合被“处理”,并且我将这些概念投射到我的心理模型上,了解EF将如何执行查询。我仍然不清楚EF的所有魔法,但是,到那里。

1 个答案:

答案 0 :(得分:3)

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

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