【问题标题】:navigation property should be virtual - not required in ef core?导航属性应该是虚拟的 - 在 ef 核心中不需要?
【发布时间】:2017-06-12 09:06:10
【问题描述】:

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

现在不需要了吗?

【问题讨论】:

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


    【解决方案1】:

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

    由于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 无关紧要。

    【讨论】:

    • @CamiloTerevinto 以防万一?默认?现在真的无所谓了。
    • @AntoinePelletier 我也不知道——我根本没有使用脚手架。但是了解当前的 EF Core 状态 - 错误、不完整的功能、简单有效查询的奇怪内部异常、工具(特别是脚手架)应该是使用它的人不太关心的问题。
    • 目前是(无效)。不过,它可能在未来。这就是重点。
    • 在 EF Core 1.X 中使用 Scaffold-DbContext,所有导航属性都是虚拟的。我只是在升级到 EF Core 2.X 后重新搭建了脚手架,所有导航属性都不再是虚拟的。
    • @ Ivan Stoev 我在答案中注意到“由于 EF Core 尚不支持延迟加载”,因此提到它已经导致答案更新。这是我的意图。
    【解决方案2】:

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

    它有什么变化?

    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】:

      自从写出接受的答案后,情况发生了变化。在 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必需的。否则,它不是。

      【讨论】:

      • 情况发生了变化,但我的回答中的要点仍然有效 - 导航属性仍然​​不需要,除非您将自己置于它们是的情况i> 由于发布的功能不完整而需要。修复使用代理的延迟加载后,您的答案将失效,并且不再需要 virtual
      • @IvanStoev 那么我为什么要搜索这个,因为 EF6 会尝试在子集合中插入和“链接”实体,因为虚拟关键字立即让 EF6 明白其中的实体该集合可以是独立的,因此只包含对它们的引用,因此可以根据需要创建 FK。我有点担心您误解了关键字的重要性。 virtual 不仅启用了延迟加载,它还解决了我上面在一个稍微复杂的应用程序中遇到的问题。我不买它直接不需要
      • @beggarboy 这绝对不是必需的。 public ICollection&lt;SomeEntity&gt; SomeEntities { get; set; }public SomeEntity SomeEntity { get; set; } 足以让 EF 检测导航属性,从而检测关系。
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

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

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

        编辑:

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

        【讨论】:

          猜你喜欢
          • 2021-08-13
          • 1970-01-01
          • 1970-01-01
          • 2014-11-01
          • 2020-05-30
          • 2021-03-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多