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。它显示了一些通过集合 属性 有效查询相关实体的选项。
我是一名经验丰富的 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。它显示了一些通过集合 属性 有效查询相关实体的选项。