导航 属性 应该是虚拟的 - 在 ef 核心中不需要?

navigation property should be virtual - not required in ef core?

我记得在 EF navigation property should be virtual:

public class Blog 
{  
    public int BlogId { get; set; }  
    public string Name { get; set; }  
    public string Url { get; set; }  
    public string Tags { get; set; }  

    public virtual ICollection<Post> Posts { get; set; }  
}

但我看 EF Core 并不认为它是虚拟的:

public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }

不需要了吗?

在EF Core中默认选择了不鼓励延迟加载的路径。 另外我认为这个功能在这个问题之后仍然没有实现。

https://github.com/aspnet/EntityFramework/issues/3312

对于早期版本的 EF,虚拟导航属性允许延迟加载相关实体。

我想现在加载导航属性只能通过 .Include(...)

来实现

编辑:

Core 支持多种加载相关实体的方法。 如果您有兴趣:https://docs.microsoft.com/en-us/ef/core/querying/related-data

virtual 在 EF 中从未 需要 。仅当您需要延迟加载支持时才需要它。

因为 Lazy loading is not yet supported by EF Core, currently virtual have no special meaning. It would when (and if) they add lazy loading support (there is a plan 这样做了)。

更新: 从 EF Core 2.1 开始,Lazy loading is now supported. But if you don't add Microsoft.EntityFrameworkCore.Proxies 打包并通过 UseLazyLoadingProxies 启用它,原来的答案仍然适用。

但是,如果您这样做,由于在初始实施中缺少 opt-in 控件,情况就完全不同了 - 它 requires all 您的导航属性为 virtual。这对我来说毫无意义,在它得到修复之前你最好不要使用它。如果您确实需要延迟加载,请使用替代 Lazy loading without proxies 方法,在这种情况下 virtual 也无所谓。

从未要求虚拟关键字...它是可选的。

它有什么变化?

1.如果你声明你的 属性 virtual :

您的虚拟 属性(默认情况下)在查询主要对象时不会立即加载。仅当您尝试访问它或访问它的组件之一时,它才会从数据库中检索。

这就是所谓的延迟加载。

2。如果你声明它 non-virtual :

您的 属性 将(默认情况下)与主实体中的所有其他 属性 一起立即加载。这意味着您的 属性 将准备好访问:它已被检索。实体将不必再次查询数据库,因为您访问此 属性.

这叫做预加载。

我的看法:

更多时候我选择急切加载(non-virtual),因为大多数时候,我需要每个实体的每个 属性 一起使用,而不必返回查询(如果你更快真的想要一切都快)但是如果你只是偶尔访问这个 属性 一次(你没有列出任何东西)并且你更频繁地想要除了这个信息之外的其余信息,然后将它设为虚拟所以这个 属性 不会因为几次访问而减慢其余查询的速度。

希望这是清楚的...

例子:

我不会(热切地)使用虚拟的地方:

foreach(var line in query)
{
    var v = line.NotVirtual; // I access the property for every line
}

我会在哪里使用虚拟或延迟加载:

foreach(var line in query)
{
   if(line.ID == 509)        // because of this condition
   var v = line.Virtual; // I access the property only once in a while
}

最后一件事:

如果您不查询超过 1000 行的数据库,那么无论您选择什么都不会产生很大的影响。此外,您可以将这些 属性 声明为虚拟的,如果您想以相反的方式进行测试,则只需这样做(实体 4.0):

context.LazyLoadingEnabled = false;

会取消虚拟效果

编辑

对于较新版本的 EF:

WhateverEntities db = new WhateverEntities() 
db.Configuration.LazyLoadingEnabled = false;

更新:为 EF Core 2.1 计划的延迟加载的初始实现将要求将导航属性声明为虚拟。参见 https://github.com/aspnet/EntityFrameworkCore/issues/10787, and more generally to track progress on lazy loading, see https://github.com/aspnet/EntityFrameworkCore/issues/10509

自从写下接受的答案后,情况发生了变化。 2018 年,Lazy Loading is now supported as of Entity Framework Core 2.1 两种不同的方法。

两者中更简单的方法是使用代理,这将需要使用 virtual 定义需要延迟加载的属性。从链接页面引用:

The simplest way to use lazy-loading is by installing the Microsoft.EntityFrameworkCore.Proxies package and enabling it with a call to UseLazyLoadingProxies. [...] EF Core will then enable lazy-loading for any navigation property that can be overridden--that is, it must be virtual and on a class that can be inherited from.

这是提供的示例代码:

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public virtual Blog Blog { get; set; }
}

还有一种不用代理的懒加载方式,就是在数据类型的构造函数中注入ILazyLoaderThis is explained in here.

简而言之,有两种执行延迟加载的方法:使用代理和不使用代理。 virtual 必需的 当且仅当您希望通过代理支持延迟加载时。否则不是。