延迟加载导航属性返回'System.InvalidOperationException'

时间:2019-05-17 16:53:17

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

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

((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_Part Parts.ID 链接到表 Parts

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

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

Navigation Property Error

这也不是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

05/21/2019

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

我为函数编写了另一个定义,但是这次通过参数传递连接,而不是通过 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;

}

1 个答案:

答案 0 :(得分:0)

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

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

我还使用 LazyLoading 取消了使用,并开始使用 EagerLoading ,如您在下面的GetFirst函数中所注意到的。

有想法吗?

ContextProvider

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;

    }