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

时间:2017-01-26 19:14:38

标签: c# entity-framework virtual entity-framework-core navigation-properties

我记得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; }
    }

不再需要了吗?

6 个答案:

答案 0 :(得分:52)

EF中{p> virtual从未必需。只有在您需要延迟加载支持时才需要它。

Lazy loading is not yet supported by EF Core以来,目前virtual没有特殊含义。它会(以及如果)添加延迟加载支持(这样做有plan)。

更新:从EF Core 2.1开始,现在支持Lazy loading。但是,只要您不添加Microsoft.EntityFrameworkCore.Proxies包并通过UseLazyLoadingProxies启用它,原始答案仍然适用。

但是,如果您这样做,由于初始实施中缺少选择加入控制,事情会完全改变 - 需要 所有您的导航属性virtual。这对我来说没有意义,你最好不要使用它,直到它得到修复。如果您确实需要延迟加载,请使用替代Lazy loading without proxies 方法,在这种情况下virtual再次无关紧要。

答案 1 :(得分:18)

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

两者的简单方法是使用代理,这将要求使用virtual来延迟加载所需的属性。引用链接页面:

  

使用延迟加载的最简单方法是安装Microsoft.EntityFrameworkCore.Proxies包并通过调用UseLazyLoadingProxies启用它。 [...]然后,EF Core将为任何可以覆盖的导航属性启用延迟加载 - 也就是说,它必须是虚拟的,并且可以继承自可以继承的类。

以下是提供的示例代码:

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; }
}

还有另一种不使用代理进行延迟加载的方法,即将ILazyLoader注入到数据类型的构造函数中。 This is explained in here

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

答案 2 :(得分:15)

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

它有什么变化?

<强> 1。如果你宣布你的财产是虚拟的:

查询主对象时,您的虚拟财产(默认情况下)不会立即加载。只有当您尝试访问它或访问其中一个组件时,它才会从数据库中进行检索。

这称为延迟加载。

<强> 2。如果你声明它是非虚拟的:

您的财产将(默认情况下)立即加载到您的主要实体中的所有其他财产。这意味着您的财产将可以访问:它已经被检索。由于您访问此属性,实体不必再次查询数据库。

这称为急切加载。

我的观点:

我经常选择急切加载(非虚拟),因为大多数时候,我需要使用每个实体的每个属性而不必回复(如果你真的想要快速的话,请更快)但是如果你偶尔访问此属性一次(您没有列出任何内容),并且您希望更多地通常只有其余的信息来执行此操作,然后将其设置为虚拟,以便此属性不会减慢查询的其余部分一些访问。

希望这很清楚......

例子:

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

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
}

最后一件事:

如果您不查询超过1 000行数据库,那么您选择的任何内容都不会产生重大影响。此外,您可以将这些属性声明为虚拟,如果您想要反过来测试,则只需执行此操作(实体4.0):

context.LazyLoadingEnabled = false;

它将取消虚拟效果。

修改

对于较新版本的EF:

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

答案 3 :(得分:3)

在EF Core中,默认情况下选择了阻止延迟加载的路径。 此外,我认为在此问题之后仍未实现此功能。

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

使用以前版本的EF,虚拟导航属性允许延迟加载相关实体。

我想现在只能使用.Include(...)

来加载导航属性

编辑:

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

答案 4 :(得分:1)

更新:计划用于EF Core 2.1的延迟加载的初始实现将要求将导航属性声明为虚拟。请参阅https://github.com/aspnet/EntityFrameworkCore/issues/10787,更一般地说,要跟踪延迟加载的进度,请参阅https://github.com/aspnet/EntityFrameworkCore/issues/10509

答案 5 :(得分:0)

如果您定义虚拟的导航属性,则Entity Framework将在运行时创建一个从您的类派生的新类(动态代理),并使用它代替原始类。这个新动态创建的类包含用于在首次访问时加载导航属性的逻辑。这称为“延迟加载”。它使Entity Framework避免加载数据库中不需要的整个依赖对象树。 https://dipoletechi.com/blog-post/virtual-in-entity-framework/ 问候 阿坎沙