我对Lazy加载工作的方式感到困惑。
例如,如果我有供应商对象,它将Address外部对象作为属性,如下所示:
public class Supplier
{
public int ID { get; set; }
[Required]
public string FullName { get; set; }
public string TaxNumber { get; set; }
public virtual Address DeliveryAddress { get; set; }
}
当我把断点放在:
var suppliers = dbContext.Supplier.ToList();
我可以看到var供应商等可以使用地址信息。当我使用DeliveryAddress属性时,它是可用的,这是否意味着所有FK对象都已加载?但另一方面,对于右侧的查询,我可以在断点处从Visual Studio查看,就像这样:
{SELECT
[Extent1].[ID] AS [ID],
[Extent1].[FullName] AS [FullName],
[Extent1].[TaxNumber] AS [TaxNumber],
[Extent1].[DeliveryAddress_ID] AS [DeliveryAddress_ID]
FROM [dbo].[Suppliers] AS [Extent1]}
这意味着查询本身根本不会加载Address对象吗?
那么谁在加载FK对象? ToList()或VS调试器?
关于如何确认是否是延迟加载的其他建议?
注意:现在我确认Lazy加载正在通过两个ToList调用,一个设置Lazy加载,另一个设置延迟加载。有人可以指点我知道什么时候延迟加载另一个查询是为FK属性发送的吗?
答案 0 :(得分:6)
VS调试器加载相关对象,它发生在第二个SQL查询中,而不是您在问题中显示的查询。在调试器中钻取地址对象时,调试器将访问对象的属性以显示其值。访问此对象会触发延迟加载和第二个SQL查询。
修改强>
这是有效的,因为父对象不是您的Supplier
类型,而是一个派生自Supplier
(“代理”)的类。此派生类是在运行时动态创建的,并且具有一些神秘的自动生成名称(您应该在调试器中看到此类名)。此动态类具有与基础Supplier
相同的属性,但它已重载DeliveryAddress
属性。 (这就是为什么这些导航属性必须是virtual
的原因,否则将无法进行重载。)查询使用已经与供应商查询一起提取的FK列值,并通过此值检索地址。 / p>
当您或调试器使用DeliveryAddress
访问属性时调用的重载supplier.DeliveryAddress
属性的新getter包含运行时生成的代码,该代码运行SQL查询以从数据库加载相关对象。派生代理类包含各种其他内部成员,尤其是对上下文/数据库连接的引用(以便能够运行查询)和一个标志,该标志指示代理对象已经加载了导航属性,以便当您第二次访问DeliveryAddress
时,它不会运行第二个冗余查询。
这就是POCO延迟加载的方式。