实体框架:为什么虚拟关键字用于在DbContext中声明属性



i很少使用EF。所以我有个问题。如果我们不在dbset中使用virtual关键字,那么惰性加载将不起作用?

我从这个链接上读到一篇文章https://stackoverflow.com/a/24114284/5314244他们提供类似的代码

public class AppContext : DbContext
{
public AppContext()
{
Configuration.LazyLoadingEnabled = true;
}
public virtual DbSet<AccountType> AccountTypes { get; set; }
}
public class AccountType
{
public Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<AccountCode> AccountCodes { get; set; }
}
public class AccountCode
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid AccountTypeId { get; set; }
public virtual AccountType AccountType { get; set; }
}

他们说:

The virtual keyword on the navigation properties are used to enable lazy loading mechanism, but the LazyLoadingEnabled property of the configuration must be enabled.
The virtual keyword on AccountType::AccountCodes navigation property will load all account codes the moment there is a programmatically access to that property while the db context are still alive

如果我们声明这个代码没有虚拟关键字public DbSet<AccountType> AccountTypes { get; set; },那么当这行execute var accountCodes = accountType.AccountCodes;时会发生什么?

是否会抛出错误或将null存储在accountCodes变量中?

第二个问题是EF--->懒惰加载或渴望加载中的默认值是什么?有多少种类型的装载选项可用?

感谢

您想要实现的方法,即延迟加载,意味着数据提供商(在您的案例中为Entity Framework)在您需要的时候检索某些数据。例如,如果您访问所有帐户类型,则可能不需要访问这些帐户类型的所有帐户代码,因此不需要从数据库中检索它们。

如果您必须自己编写SQL,那么您很可能会在不加入子关系的情况下编写一个纯select语句:

SELECT * FROM AccountTypes;

另一方面,另一个用例可能需要访问这些数据,因此您可能会急切地加载它,从而导致连接操作。。。

SELECT * FROM AccountTypes JOIN AccountCodes ON AccountCodes.AccountTypeId = AccountTypes.Id;

或者依赖实体框架的惰性加载能力。

后一种情况要求实体框架执行以下操作:首先,选择所有帐户类型,然后,在用户代码访问帐户代码时,发出另一个选择语句来检索相应帐户类型的代码。为此,实体框架需要一个钩子,即它必须知道您何时访问导航属性,这通常是不可能的,因为这需要在该属性的getter中添加额外的代码:

public class AccountType
{
public Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<AccountCode> AccountCodes
{ 
get { /* Load child data here */ }
set { /* ... */ }
}
}

不幸的是,实体框架无法更改POCO类,因为它是您的用户代码,但它可以做的是从您的类派生并重写属性以注入它的魔力。为了实现这一点,它创建了所谓的代理,即在运行时创建一个派生自POCO类的类,如:

public class AccountTypeProxy : AccountType
{
public override ICollection<AccountCode> AccountCodes
{ 
get { /* Load child data here */ }
set { /* ... */ }
}
}

因此,当您检索帐户类型时,您得到的实际上是一堆代理实例,您可以在调试期间确认这些代理实例。

如果不将虚拟关键字添加到导航属性或密封类,则Entity Framework无法覆盖该属性或根本无法从该类派生,因此延迟加载将不起作用。

最新更新