【问题标题】:Lazy Loading navigation properties returns 'System.InvalidOperationException'延迟加载导航属性返回“System.InvalidOperationException”
【发布时间】:2019-05-17 16:53:17
【问题描述】:

我一直在将使用 EF6 的 VB.net 应用程序迁移到使用 EF-Core 3.0 的 C# .Net Core 应用程序。我一直使用 EF 作为 DB-First。使用 EF-Core,我需要指定我想要加载我的值的方式。因为我经常需要访问许多导航属性(通过 FK 链接到其他表),所以我宁愿使用 Lazy Load 而不是管理 Eager Loads。但是每当我想这样做时,我都会在导航属性上收到此错误:

((Castle.Proxies.WillyDemandesProxy)willyDemandes).IdPartNavigation threw an exception of type 'System.InvalidOperationException' : Error generated for warning 'Microsoft.EntityFrameworkCore.Infrastructure.LazyLoadOnDisposedContextWarning: An attempt was made to lazy-load navigation property 'IdPartNavigation' on entity type 'WillyDemandesProxy' after the associated DbContext was disposed.'. This exception can be suppressed or logged by passing event ID 'CoreEventId.LazyLoadOnDisposedContextWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.

WillyDemandes 通过外键链接到表 Parts,使用 WillyDemande.Id_PartParts.ID

当您使用 EF-Core DB-First 构建 DbContext 时,它会创建名为“Navigation Properties”的虚拟属性,以便您轻松访问其他表中的链接信息。 p>

每当您尝试访问 IDPartNavigation 时都会引发异常。这是一个例子:

它也不是 100% 发生的。

有什么想法吗?

上下文

    /// <summary>
    /// https://docs.microsoft.com/en-us/ef/core/querying/related-data
    /// </summary>
    /// <param name="optionsBuilder"></param>
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseLazyLoadingProxies();
            //optionsBuilder.ConfigureWarnings(warnings => warnings.Default(WarningBehavior.Ignore));
            optionsBuilder.UseSqlServer("Server=TRBSQL02;Database=Info_Indus;Trusted_Connection=True;");
        }
    }

功能

    static public WillyDemandes GetFirst()
    {

        using (Info_IndusContext conn = new Info_IndusContext())
        {
            WillyDemandes willyDemandes;

                willyDemandes = conn.WillyDemandes
                    .Where(x => x.Statut == Statuts.EnTest.ToString() && x.Username == Environment.UserName)
                    //.Include(x=>x.IdPartNavigation)
                    .OrderBy(x => x.Priority)
                    .ThenBy(x => x.Id)
                    .FirstOrDefault();


            if (willyDemandes != null)
            {
                willyDemandes.Statut = Statuts.EnTraitement.ToString();
                willyDemandes.ServerName = Environment.MachineName;
                willyDemandes.DateDebut = DateTime.Now;
                conn.SaveChanges();
                conn.Entry(willyDemandes).GetDatabaseValues();
                conn.Entry(willyDemandes).Reload();
            }

            return willyDemandes;
        }
    }

以前在 Vb.Net 中

Public Function Demande_GetFirst() As WillyDemandes

        Dim conn As New Info_IndusEntities(False)

        Dim DemandeWilly As WillyDemandes = conn.WillyDemandes.Where(Function(x) x.Statut = Statuts.EnTest.ToString AndAlso x.Username = Environment.UserName).OrderBy(Function(x) x.Priority).ThenBy(Function(x) x.ID).FirstOrDefault

        If Not IsNothing(DemandeWilly) Then
            DemandeWilly.Statut = Statuts.EnTraitement.ToString
            DemandeWilly.ServerName = Environment.MachineName
            DemandeWilly.DateDebut = DateTime.Now
            conn.SaveChanges()
        End If

        Return DemandeWilly

    End Function

2019 年 5 月 21 日

错误似乎与 DbContext 的范围有关。当您将 USINGPROXIES 结合使用时,就会发生这种情况。

我已经为我的函数编写了另一个定义,但这次是通过参数传递连接,而不是使用 USING 在函数内部创建它。然后,只要 DbContext 存在,代理就可以使用。

    static public WillyDemandes GetFirst(Info_IndusContext conn)
{


    WillyDemandes willyDemandes;


        willyDemandes = conn.WillyDemandes
            .Where(x => x.Statut == Statuts.EnTest.ToString() && x.Username == Environment.UserName)
            //.Include(x=>x.IdPartNavigation)
            .OrderBy(x => x.Priority)
            .ThenBy(x => x.Id)
            .FirstOrDefault();

    if (willyDemandes != null)
    {
        willyDemandes.Statut = Statuts.EnTraitement.ToString();
        willyDemandes.ServerName = Environment.MachineName;
        willyDemandes.DateDebut = DateTime.Now;
        conn.SaveChanges();
        conn.Entry(willyDemandes).GetDatabaseValues();
        conn.Entry(willyDemandes).Reload();
    }

    return willyDemandes;

}

【问题讨论】:

  • EF 3 仍处于预览阶段;期待这样的错误。你最好在那里报告它,并附上重现错误的可运行代码。
  • 我尝试回滚到 EF 2.2.4 但错误仍然存​​在。
  • 那么,哪一行抛出异常,IdPartNavigation 是什么?你最好显示相关的类。
  • @GertArnold 我已经编辑了原始帖子。从来没有做过这种事的人很难理解。但我只是希望有一天有人偶然发现这篇文章并给出某种答案。
  • 编辑后 - 现在很明显,您遇到了一个非常常见的异常,该异常与在处理上下文后触发延迟加载有关。无论有没有using,你都应该避免这种情况。 IMO,最好禁用延迟加载并在必要时使用新上下文获取数据。

标签: c# entity-framework-core visual-studio-2019 .net-core-3.0


【解决方案1】:

所以我找到了解决这个问题的方法,但我怀疑这是最好的解决方案

基本上我所做的是创建了一个 ContextProvider 类,它允许我创建每个人都可以访问的 1 个 Info_IndusContext。我还删除了我的控制器的所有 USING 语句。

我也放弃了使用 LazyLoading 并开始使用 EagerLoading,您可能会在下面的 GetFirst 函数中注意到。

想法?

上下文提供者

using WillyServer.Models;
namespace WillyServer.Controllers
{
    public static class ContextProvider
    {
        public static Info_IndusContext db = new Info_IndusContext();
    }
}

WillyDemandesController.GetFirst

    static public WillyDemandes GetFirst()
    {

   WillyDemandes willyDemandes = ContextProvider.db.WillyDemandes
                .Include(x => x.IdPartNavigation)
                .Include(x => x.WillyMachines)
                .Where(x => x.Statut == Statuts.EnTest.ToString() && x.Username == Environment.UserName)
                .OrderBy(x => x.Priority)
                .ThenBy(x => x.Id)
                .FirstOrDefault();

        if (willyDemandes != null)
        {
            willyDemandes.Statut = Statuts.EnTraitement.ToString();
            willyDemandes.ServerName = Environment.MachineName;
            willyDemandes.DateDebut = DateTime.Now;
            ContextProvider.db.SaveChanges();
        }

        return willyDemandes;

    }

【讨论】:

  • 您所描述的内容在 C# 和 VB.NET、Core 或非 Core 以及任何 EF 版本中都是相同的。如果上下文被释放,你不能使用延迟加载。上下文,就像数据库连接一样是短暂的,应该尽快处理,尤其是在 Web 应用程序中。在 VB.NET 中不会出现此错误的唯一原因是 dcontext 没有被处理掉。其他 ORM 也是如此。保持 DbContext 或 Session 处于活动状态是一个坏主意,因为它们会随着时间的推移跟踪越来越多的对象
  • @PanagiotisKanavos 好的!我正在考虑另一种可能比这个更好的解决方案!
猜你喜欢
  • 1970-01-01
  • 2012-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多