[英]Entity Framework: Why virtual keyword used to declare properties in DbContext
i rare use EF. 我很少使用EF。 so i have a question. 所以我有一个问题。 if we do not use virtual keyword with dbset then lazy load will not work? 如果我们不将virtual关键字与dbset一起使用,那么延迟加载将不起作用?
i read a article from this link https://stackoverflow.com/a/24114284/5314244 they provide code like 我从此链接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; }
}
they said : 他们说 :
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
if we declare this code without virtual keyword public DbSet<AccountType> AccountTypes { get; set; }
如果我们声明此代码时没有虚拟关键字public DbSet<AccountType> AccountTypes { get; set; }
public DbSet<AccountType> AccountTypes { get; set; }
public DbSet<AccountType> AccountTypes { get; set; }
then when this line execute var accountCodes = accountType.AccountCodes;
public DbSet<AccountType> AccountTypes { get; set; }
然后在此行execute var accountCodes = accountType.AccountCodes;
what will happen? 会发生什么?
Error will thrown or null will be stored in accountCodes
variable? 将抛出错误还是将null存储在accountCodes
变量中?
second question what is default in EF---> lazy load or eager loading? 第二个问题是EF --->延迟加载或渴望加载中的默认设置是什么? how many type of loading option available ? 有多少种加载选项可用?
thanks 谢谢
The approach you want to achieve, lazy loading, means that the data provider, in your case Entity Framework, retrieves certain data at the time you need it. 延迟加载是您要实现的方法,这意味着数据提供程序(在您的情况下为Entity Framework)会在需要时检索某些数据。 If, for example, you access all account types you probably don't need to access all account codes for these account types thus retrieving them from the database would be unnecessary. 例如,如果您访问所有帐户类型,则可能不需要访问这些帐户类型的所有帐户代码,因此从数据库中检索它们是不必要的。
If you had to write the SQL yourself, you would most likely write a plain select statement without joining the child relations: 如果必须自己编写SQL,则很可能在不加入子关系的情况下编写普通的select语句:
SELECT * FROM AccountTypes;
Another use-case on the other hand might need access to this data so you would either end up with eagerly loading it which results in a join operation... 另一方面,另一个用例可能需要访问此数据,因此您要么会急于加载它,最终导致联接操作...
SELECT * FROM AccountTypes JOIN AccountCodes ON AccountCodes.AccountTypeId = AccountTypes.Id;
...or to rely on Entity Framework's lazy loading ability. ...或依靠Entity Framework的延迟加载功能。
The latter case requires Entity Framework to do the following: First, selecting all account types and then, at the time your user-code accesses the account codes, emitting another select statement to retrieve the codes for the respective account type. 在后一种情况下,Entity Framework需要执行以下操作:首先,选择所有帐户类型,然后在您的用户代码访问帐户代码时,发出另一个select语句以检索相应帐户类型的代码。 To do so, Entity Framework needs a hook, ie it must know when you access the navigation property, which is in general impossible because this would need additional code in the getter of this property: 为此,实体框架需要一个钩子,即它必须知道何时访问导航属性,这通常是不可能的,因为在此属性的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 { /* ... */ }
}
}
Unfortunately Entity Framework is unable to alter the POCO class because it's your user-code , but what it can do is deriving from your class and overriding the property to inject it's magic. 不幸的是,Entity Framework无法更改POCO类,因为它是您的用户代码 ,但是它能做的是从您的类派生并重写该属性以注入魔力。 For this to work it creates what is called a proxy , ie it creates a class at runtime which derives from your POCO class, like: 为此,它创建了一个称为proxy的代理 ,即,它在运行时创建了一个从POCO类派生的类,例如:
public class AccountTypeProxy : AccountType
{
public override ICollection<AccountCode> AccountCodes
{
get { /* Load child data here */ }
set { /* ... */ }
}
}
So what you get when you retrieve the account types is actually a bunch of proxy instances, which you can confirm during debugging. 因此,检索帐户类型时得到的实际上是一堆代理实例,您可以在调试过程中进行确认。
If you would not add the virtual keyword to the navigation property or if you sealed the class, Entity Framework could not override the property or could not derive from the class at all and thus lazy loading would not work. 如果您不将virtual关键字添加到navigation属性,或者如果您密封了该类,则Entity Framework无法覆盖该属性或完全不能从该类派生,因此延迟加载将无法进行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.