Résolution “L’instance ObjectContext a été supprimée et ne peut plus être utilisée pour des opérations nécessitant une connexion” InvalidOperationException

J’essaie de remplir un GridView utilisant Entity Frameworkm mais chaque fois que j’obtiens l’erreur suivante:

“L’extracteur de propriété ‘LoanProduct’ sur l’object ‘COSIS_DAL.MemberLoan’ a créé l’exception suivante: l’instance ObjectContext a été supprimée et ne peut plus être utilisée pour des opérations nécessitant une connexion.”

Mon code est:

  public List GetAllMembersForLoan(ssortingng keyword) { using (CosisEntities db = new CosisEntities()) { IQueryable query = db.MemberLoans.OrderByDescending(m => m.LoanDate); if (!ssortingng.IsNullOrEmpty(keyword)) { keyword = keyword.ToLower(); query = query.Where(m => m.LoanProviderCode.Contains(keyword) || m.MemNo.Contains(keyword) || (!ssortingng.IsNullOrEmpty(m.LoanProduct.LoanProductName) && m.LoanProduct.LoanProductName.ToLower().Contains(keyword)) || m.Membership.MemName.Contains(keyword) || m.GeneralMasterInformation.Description.Contains(keyword) ); } return query.ToList(); } } protected void btnSearch_Click(object sender, ImageClickEventArgs e) { ssortingng keyword = txtKeyword.Text.ToLower(); LoanController c = new LoanController(); List list = new List(); list = c.GetAllMembersForLoan(keyword); if (list.Count <= 0) { lblMsg.Text = "No Records Found"; GridView1.DataSourceID = null; GridView1.DataSource = null; GridView1.DataBind(); } else { lblMsg.Text = ""; GridView1.DataSourceID = null; GridView1.DataSource = list; GridView1.DataBind(); } } 

L’erreur mentionne la colonne LoanProductName de la vue Gridview . Mentionné: J’utilise C #, ASP.net, SQL-Server 2008 comme firebase database principale.

Je suis assez nouveau pour Entity Framework. Je ne peux pas comprendre pourquoi je reçois cette erreur. Quelqu’un peut-il m’aider s’il-vous-plaît?

Par défaut, Entity Framework utilise le chargement différé pour les propriétés de navigation. C’est pourquoi ces propriétés doivent être marquées comme virtuelles – EF crée une classe proxy pour votre entité et remplace les propriétés de navigation pour permettre le chargement différé. Par exemple, si vous avez cette entité:

 public class MemberLoan { public ssortingng LoandProviderCode { get; set; } public virtual Membership Membership { get; set; } } 

Entity Framework renverra le proxy hérité de cette entité et fournira l’instance DbContext à ce proxy afin de permettre le chargement tardif de l’appartenance ultérieurement:

 public class MemberLoanProxy : MemberLoan { private CosisEntities db; private int membershipId; private Membership membership; public override Membership Membership { get { if (membership == null) membership = db.Memberships.Find(membershipId); return membership; } set { membership = value; } } } 

Ainsi, l’entité a une instance de DbContext utilisée pour charger une entité. C’est ton problème. Vous using bloc autour de l’utilisation de CosisEntities. Qui dispose du contexte avant que les entités ne soient renvoyées. Lorsqu’un code tente ultérieurement d’utiliser la propriété de navigation par chargement différé, il échoue car le contexte est éliminé à ce moment.

Pour résoudre ce problème, vous pouvez utiliser le chargement rapide des propriétés de navigation dont vous aurez besoin plus tard:

 IQueryable query = db.MemberLoans.Include(m => m.Membership); 

Cela pré-chargera toutes les adhésions et le chargement paresseux ne sera pas utilisé. Pour plus de détails, voir l’ article relatif au chargement des entités associées sur MSDN.

La classe CosisEntities est votre DbContext . Lorsque vous créez un contexte dans un bloc d’ using , vous définissez les limites de votre opération orientée données.

Dans votre code, vous essayez d’émettre le résultat d’une requête à partir d’une méthode, puis vous terminez le contexte dans la méthode. L’opération à laquelle vous transmettez le résultat tente ensuite d’accéder aux entités afin de remplir la vue de grid. Quelque part dans le processus de liaison à la grid, une propriété paresseuse est en cours d’access et Entity Framework tente d’effectuer une recherche pour obtenir les valeurs. Il échoue car le contexte associé est déjà terminé.

Vous avez deux problèmes:

  1. Vous chargez des entités paresseuses lorsque vous vous connectez à la grid. Cela signifie que vous effectuez de nombreuses opérations de requête distinctes sur SQL Server, qui vont tout ralentir. Vous pouvez résoudre ce problème en rendant les propriétés associées chargées par défaut par défaut ou en demandant à Entity Framework de les inclure dans les résultats de cette requête à l’aide de la méthode d’extension Include .

  2. Vous mettez fin à votre contexte de manière prématurée: un contexte DbContext devrait être disponible dans l’unité de travail en cours, ne le disposant que lorsque vous avez terminé le travail en cours. Dans le cas d’ASP.NET, une unité de travail est généralement la requête HTTP en cours de traitement.

Bottom Line

Votre code a récupéré des données (entités) via l’entité-framework avec chargement différé activé et après l’élimination de DbContext, votre code fait référence aux propriétés (entités liées / relation / navigation) qui n’ont pas été explicitement demandées.

Plus précisement

InvalidOperationException avec ce message signifie toujours la même chose: vous demandez des données (entités) à partir de l’entité-framework après l’élimination de DbContext.

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 que des tables sont associées dans la firebase database)

 public class Person { public int Id { get; set; } public ssortingng name { get; set; } public int? PetId { get; set; } public Pet Pet { get; set; } } public class Pet { public ssortingng 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 InvalidOperationException car dbContext n’a pas désactivé le chargement différé et le code accède à la propriété de navigation Pet après que le contexte ait été supprimé par l’instruction using.

Le débogage

Comment trouvez-vous la source de cette exception? En plus de l’exception elle-même, qui sera renvoyé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 inspectez vos variables , en passant la souris sur leurs noms, ouvrant un Quick) Regardez la fenêtre ou utilisez les différents panneaux de débogage tels que Locals et Autos.

Si vous voulez savoir où la référence est ou non définie, cliquez avec le bouton droit sur son nom et sélectionnez “Rechercher toutes les références”. Vous pouvez ensuite placer un point d’arrêt à chaque emplacement qui demande des données et exécuter votre programme avec le débogueur associé. Chaque fois que le débogueur se casse sur un tel point d’arrêt, vous devez déterminer si votre propriété de navigation doit avoir été renseignée ou si les données demandées sont nécessaires.

Façons d’éviter

Désactiver le chargement différé

 public class MyDbContext : DbContext { public MyDbContext() { this.Configuration.LazyLoadingEnabled = false; } } 

Pour: Au lieu de lancer InvalidOperationException, la propriété sera null. L’access aux propriétés null ou la tentative de modification des propriétés de cette propriété déclencheront une exception NullReferenceException .

Comment demander explicitement l’object 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 en plus de la personne. Cela peut être avantageux car il s’agit d’un seul appel à la firebase database. (Cependant, le nombre de résultats renvoyés et le nombre de propriétés de navigation demandées peuvent également entraîner d’énormes problèmes de performances. Dans ce cas, il n’y aura aucune pénalisation des performances car les deux instances ne sont qu’un enregistrement unique et une jointure unique).

ou

 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 indépendamment de la personne en effectuant un appel supplémentaire à la firebase database. Par défaut, Entity Framework suit les objects qu’il a extraits de la firebase database et, s’il trouve des propriétés de navigation correspondantes, les remplit automatiquement . Dans cette instance, car PetId sur l’object Person correspond à Pet.Id , Entity Framework affectera le Person.Pet à la valeur Pet récupérée 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 est une demande de données via Entity Framework. Lorsque le code renvoie une exception de référence null sur une propriété d’une entité, vous pouvez presque toujours vous assurer que vous n’avez pas explicitement demandé ces données.

C’est une réponse très tardive mais j’ai résolu le problème en désactivant le chargement paresseux:

 db.Configuration.LazyLoadingEnabled = false; 

Dans mon cas, je transmettais tous les modèles des utilisateurs à la colonne et celle-ci n’était pas mappée correctement, alors j’ai juste passé ‘Users.Name’ et le problème a été résolu.

 var data = db.ApplicationTranceLogs .Include(q=>q.Users) .Include(q => q.LookupItems) .Select(q => new { Id = q.Id, FormatDate = q.Date.ToSsortingng("yyyy/MM/dd"), ***Users = q.Users,*** ProcessType = q.ProcessType, CoreProcessId = q.CoreProcessId, Data = q.Data }) .ToList(); var data = db.ApplicationTranceLogs .Include(q=>q.Users).Include(q => q.LookupItems) .Select(q => new { Id = q.Id, FormatDate = q.Date.ToSsortingng("yyyy/MM/dd"), ***Users = q.Users.Name***, ProcessType = q.ProcessType, CoreProcessId = q.CoreProcessId, Data = q.Data }) .ToList(); 

La plupart des autres réponses indiquent un chargement rapide, mais j’ai trouvé une autre solution.

Dans mon cas, j’avais un object EF InventoryItem avec une collection d’objects enfants InvActivity .

 class InventoryItem { ... // EF code first declaration of a cross table relationship public virtual List ItemsActivity { get; set; } public GetLatestActivity() { return ItemActivity?.OrderByDescending(x => x.DateEntered).SingleOrDefault(); } ... } 

Et comme je tirais de la collection d’objects enfants au lieu d’une requête de contexte (avec IQueryable ), la fonction Include() n’était pas disponible pour implémenter un chargement rapide. Au lieu de cela, ma solution consistait à créer un contexte à partir duquel j’utilisais GetLatestActivity() et attach() l’object renvoyé:

 using (DBContext ctx = new DBContext()) { var latestAct = _item.GetLatestActivity(); // attach the Entity object back to a usable database context ctx.InventoryActivity.Attach(latestAct); // your code that would make use of the latestAct's lazy loading // ie latestAct.lazyLoadedChild.name = "foo"; } 

Ainsi, vous n’êtes pas coincé avec un chargement impatient.