首页 > 解决方案 > 延迟加载导航属性返回“System.InvalidOperationException”

问题描述

我一直在将使用 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使用WillyDemande.Id_PartParts.ID通过外键链接到表Parts

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

每当您尝试访问 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;

}

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

解决方案


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

基本上我所做的是我创建了一个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;

    }

推荐阅读