Ligne de fond
Votre code a récupéré des données (entités) via entity-framework avec lazy-loading activé et après que le DbContext ait été disposé, votre code fait référence à des propriétés (entités liées/relations/navigation) qui n'ont pas été explicitement demandées.
Plus précisément
El InvalidOperationException
avec ce message signifie toujours la même chose : vous demandez des données (entités) à entity-framework après que le DbContext ait été éliminé.
Un cas simple :
(ces classes seront utilisées pour tous les exemples de cette réponse, et supposent que toutes les propriétés de navigation ont été configurées correctement et ont des tables associées dans la base de données)
public class Person
{
public int Id { get; set; }
public string name { get; set; }
public int? PetId { get; set; }
public Pet Pet { get; set; }
}
public class Pet
{
public string name { get; set; }
}
using (var db = new dbContext())
{
var person = db.Persons.FirstOrDefaultAsync(p => p.id == 1);
}
Console.WriteLine(person.Pet.Name);
La dernière ligne lancera le InvalidOperationException
parce que le dbContext n'a pas désactivé le chargement paresseux et que le code accède à la propriété de navigation Pet après que le Context a été éliminé par l'instruction using.
Débogage
Comment trouver la source de cette exception ? Outre l'examen de l'exception elle-même, qui sera levée exactement à l'endroit où elle se produit, les règles générales de débogage dans Visual Studio s'appliquent : placez des points d'arrêt stratégiques et des points de contrôle. contrôlez vos variables soit en passant la souris sur leur nom, en ouvrant une fenêtre (Quick)Watch ou en utilisant les différents panneaux de débogage comme Locals et Autos.
Si vous voulez savoir où se trouve ou ne se trouve pas la référence, faites un clic droit sur son nom et sélectionnez "Rechercher toutes les références". Vous pouvez alors placer un point d'arrêt à chaque endroit qui demande des données, et exécuter votre programme avec le débogueur attaché. Chaque fois que le débogueur s'arrête sur un tel point d'arrêt, vous devez déterminer si votre propriété de navigation aurait dû être remplie ou si les données demandées sont nécessaires.
Les moyens d'éviter
Désactiver le Lazy-Loading
public class MyDbContext : DbContext
{
public MyDbContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
Pour : Au lieu de lancer l'exception InvalidOperationException, la propriété sera nulle. Accéder aux propriétés de null ou essayer de changer les propriétés de cette propriété lèvera une NullReferenceException .
Comment demander explicitement l'objet en cas de besoin :
using (var db = new dbContext())
{
var person = db.Persons
.Include(p => p.Pet)
.FirstOrDefaultAsync(p => p.id == 1);
}
Console.WriteLine(person.Pet.Name); // No Exception Thrown
Dans l'exemple précédent, Entity Framework matérialisera l'animal de compagnie en plus de la personne. Cela peut être avantageux car il s'agit d'un appel unique à la base de données. (Cependant, il peut aussi y avoir d'énormes problèmes de performance en fonction du nombre de résultats retournés et du nombre de propriétés de navigation demandées, dans ce cas, il n'y aurait pas de pénalité de performance car les deux instances ne sont qu'un seul enregistrement et une seule jointure).
o
using (var db = new dbContext())
{
var person = db.Persons.FirstOrDefaultAsync(p => p.id == 1);
var pet = db.Pets.FirstOrDefaultAsync(p => p.id == person.PetId);
}
Console.WriteLine(person.Pet.Name); // No Exception Thrown
Dans l'exemple précédent, Entity Framework matérialisera l'animal de compagnie indépendamment de la personne en effectuant un appel supplémentaire à la base de données. Par défaut, Entity Framework suit les objets qu'il a récupérés dans la base de données et s'il trouve des propriétés de navigation qui correspondent, il va auto-magique de peupler ces entités. Dans ce cas, parce que le PetId
sur le Person
correspond à l'objet Pet.Id
Entity Framework attribuera l'adresse Person.Pet
a la Pet
récupéré, avant que la valeur ne soit affectée à la variable pet.
Je recommande toujours cette approche car elle oblige les programmeurs à comprendre quand et comment le code demande des données via Entity Framework. Lorsque le code lève une exception de référence nulle sur une propriété d'une entité, vous pouvez presque toujours être sûr que vous n'avez pas explicitement demandé ces données.