Свойства навигации с отложенной загрузкой возвращают исключение System.InvalidOperationException
Я переносил приложение 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. Вот пример:
Это также происходит не в 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 ответ
Поэтому я нашел способ справиться с этим, но сомневаюсь, что это лучшее из решений.
По сути, я создал класс 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;
}