Свойства навигации с отложенной загрузкой возвращают исключение System.InvalidOperationException - PullRequest
3 голосов
/ 17 мая 2019

Я переносил приложение VB.net с использованием EF6 в приложение C # .Net Core с использованием EF-Core 3.0.Я всегда использовал 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_Part и Parts.ID .

Когда вы создаете свой DbContext с помощью EF-Core DB-First, он создает виртуальные свойства, называемые " Свойства навигации ", чтобы вы могли легко получить доступ к связанной информации в других таблицах.

Исключение выдается при попытке доступа к 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 и PROXIES .

Я написал другое определение моей функции, но на этот раз, передавая соединение через параметры вместо создания его внутрифункция с 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 голосов
/ 24 мая 2019

Итак, я нашел способ справиться с этим, но я сомневаюсь, что это лучшее из решений .

По сути, я создал класс 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;

    }
...