L’opération ne peut pas être terminée car l’erreur DbContext a été supprimée.

Je suis nouveau sur EF et j’essaie d’utiliser une méthode d’extension qui convertit mon type de firebase database User en ma classe d’informations UserInfo .
J’utilise d’abord la firebase database si cela fait une différence?

Mon code ci-dessous donne l’erreur

L’opération ne peut pas être terminée car le DbContext a été supprimé.

 try { IQueryable users; using (var dataContext = new dataContext()) { users = dataContext.Users .Where(x => x.AccountID == accountId && x.IsAdmin == false); if(users.Any() == false) { return null; } } return users.Select(x => x.ToInfo()).ToList(); // this line is the problem } catch (Exception ex) { //... } 

Je peux voir pourquoi il le ferait, mais je ne comprends pas non plus pourquoi le résultat de l’instruction where n’est pas enregistré dans l’object users .

Je suppose donc que ma principale question est de savoir pourquoi cela ne fonctionne pas et, en second lieu, quelle est la bonne façon d’utiliser les méthodes d’extension et EF?

Cette question-réponse m’a amené à croire que IQueryable nécessite un contexte actif pour son fonctionnement. Cela signifie que vous devriez plutôt essayer ceci:

 try { IQueryable users; using (var dataContext = new dataContext()) { users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false); if(users.Any() == false) { return null; } else { return users.Select(x => x.ToInfo()).ToList(); // this line is the problem } } } catch (Exception ex) { ... } 

Les objects exposés comme IQueryable et IEnumerable ne s’exécutent pas réellement tant qu’ils ne sont pas itérés ou auxquels ils ne sont pas utilisés, par exemple s’ils sont composés dans une List . Lorsque EF renvoie un IQueryable il ne s’agit que de composer quelque chose capable de récupérer des données, il n’effectue pas la récupération tant que vous ne la consumz pas.

Vous pouvez avoir une idée de cela en mettant un point d’arrêt où IQueryable est défini, par .ToList() l’ .ToList() . (Depuis l’intérieur de l’étendue du contexte de données, comme Jofry l’a correctement souligné.) Le travail d’extraction des données est effectué pendant l’appel ToList() .

Pour cette raison, vous devez conserver IQueryable dans la scope du contexte de données.

N’oubliez pas que les requêtes IQueryable ne sont pas exécutées sur le magasin de données tant que vous ne les avez pas énumérées.

 using (var dataContext = new dataContext()) { 

Cette ligne de code ne fait en réalité rien d’autre que de construire l’instruction SQL

  users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false); 

.Any () est une opération qui énumère IQueryable. Le code SQL est donc envoyé à la source de données (via dataContext), puis les opérations .Any () sont exécutées sur cette source.

  if(users.Any() == false) { return null; } } 

Votre ligne “problème” réutilise le SQL construit ci-dessus, puis effectue une opération supplémentaire (.Select ()), qui ajoute simplement à la requête. Si vous l’avez laissé ici, pas d’exception, sauf votre problème

 return users.Select(x => x.ToInfo()).ToList(); // this line is the problem 

appelle .ToList (), qui énumère IQueryable, ce qui entraîne l’envoi du code SQL à la source de données via le dataContext utilisé dans la requête LINQ d’origine. Puisque ce dataContext a été supprimé, il n’est plus valide et .ToList () lève une exception.

C’est le “pourquoi ça ne marche pas”. Le correctif consiste à déplacer cette ligne de code dans la scope de votre dataContext.

Comment l’utiliser correctement est une autre question avec quelques réponses correctes qui dépendent probablement de votre application (Forms vs. ASP.net vs. MVC, etc.). Le modèle que cela implémente est le modèle d’unité de travail. La création d’un nouvel object de contexte n’entraîne pratiquement aucun coût. La règle générale consiste donc à en créer un, à effectuer votre travail, puis à le supprimer. Dans les applications Web, certaines personnes créeront un contexte par demande.

La raison pour laquelle l’erreur est générée est que l’object est supprimé et que, par la suite, nous essayons d’accéder aux valeurs de la table via l’object, mais l’object est disposé. Améliorez-le pour le convertir en ToList () afin que nous puissions avoir des valeurs

Peut-être que les données ne sont pas récupérées tant que vous ne les utilisez pas (le chargement est paresseux), de sorte que dataContext n’existe pas lorsque vous essayez de faire le travail. Je parie que si vous utilisiez la liste ToList (), tout irait bien.

 try { IQueryable users; var ret = null; using (var dataContext = new dataContext()) { users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false); if(users.Any()) { ret = users.Select(x => x.ToInfo()).ToList(); } } Return ret; } catch (Exception ex) { ... } 

Cela peut être aussi simple que d’append ToList () dans votre référentiel. Par exemple:

 public IEnumerable GetMyObjectsForId(ssortingng id) { using (var ctxt = new RcContext()) { // causes an error return ctxt.MyObjects.Where(x => x.MyObjects.Id == id); } } 

Donnera l’erreur de suppression du contexte de firebase database dans la classe appelante, mais cela peut être résolu en exerçant explicitement l’énumération en ajoutant ToList () à l’opération LINQ:

 public IEnumerable GetMyObjectsForId(ssortingng id) { using (var ctxt = new RcContext()) { return ctxt.MyObjects.Where(x => x.MyObjects.Id == id).ToList(); } } 

Change ça:

 using (var dataContext = new dataContext()) { users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false); if(users.Any()) { ret = users.Select(x => x.ToInfo()).ToList(); } } 

pour ça:

 using (var dataContext = new dataContext()) { return = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false).Select(x => x.ToInfo()).ToList(); } 

L’essentiel est que vous souhaitiez forcer l’énumération du jeu de données contextuelles une seule fois. Laissez l’appelant gérer le scénario d’un ensemble vide, comme il se doit.

Ici, vous essayez d’exécuter un object IQueryable sur un DBContext inactif. votre DBcontext est déjà éliminé. vous pouvez uniquement exécuter un object IQueryable avant la suppression de DBContext. users.Select(x => x.ToInfo()).ToList() signifie que vous devez écrire à users.Select(x => x.ToInfo()).ToList() à l’intérieur de scope