J'utilise Entity Framework et parfois j'obtiendrai cette erreur.
EntityCommandExecutionException
{"There is already an open DataReader associated with this Command which must be closed first."}
at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands...
Même si je ne fais aucune gestion de connexion manuelle.
cette erreur se produit par intermittence.
code qui déclenche l'erreur (raccourci pour faciliter la lecture):
if (critera.FromDate > x) {
t= _tEntitites.T.Where(predicate).ToList();
}
else {
t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
}
en utilisant Dispose pattern afin d'ouvrir une nouvelle connexion à chaque fois.
using (_tEntitites = new TEntities(GetEntityConnection())) {
if (critera.FromDate > x) {
t= _tEntitites.T.Where(predicate).ToList();
}
else {
t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
}
}
toujours problématique
pourquoi EF ne réutiliserait-il pas une connexion si elle était déjà ouverte.
linq
entity-framework
sql-server-2008
Sonic Soul
la source
la source
predicate
ethistoricPredicate
. J'ai découvert que si vous passezFunc<T, bool>
àWhere()
cela, il se compilera et fonctionnera parfois (car il fait le "où" en mémoire). Ce que vous devriez être en train de faire est passerExpression<Func<T, bool>>
àWhere()
.Réponses:
Il ne s'agit pas de fermer la connexion. EF gère correctement la connexion. Ma compréhension de ce problème est qu'il existe plusieurs commandes de récupération de données exécutées sur une seule connexion (ou une seule commande avec plusieurs sélections) tandis que le DataReader suivant est exécuté avant que le premier ait terminé la lecture. La seule façon d'éviter l'exception est d'autoriser plusieurs DataReaders imbriqués = activer MultipleActiveResultSets. Un autre scénario lorsque cela se produit toujours est lorsque vous parcourez le résultat de la requête (IQueryable) et que vous déclencherez un chargement paresseux pour l'entité chargée à l'intérieur de l'itération.
la source
Alternativement à l'utilisation de MARS (MultipleActiveResultSets), vous pouvez écrire votre code afin de ne pas ouvrir plusieurs jeux de résultats.
Ce que vous pouvez faire est de récupérer les données en mémoire, de cette façon, vous n'aurez pas le lecteur ouvert. Elle est souvent causée par l'itération d'un ensemble de résultats tout en essayant d'ouvrir un autre ensemble de résultats.
Exemple de code:
Disons que vous effectuez une recherche dans votre base de données contenant ces éléments:
Nous pouvons faire une solution simple à cela en ajoutant .ToList () comme ceci:
Cela oblige entityframework à charger la liste en mémoire, donc lorsque nous l'itérons dans la boucle foreach, il n'utilise plus le lecteur de données pour ouvrir la liste, il est plutôt en mémoire.
Je me rends compte que cela pourrait ne pas être souhaité si vous voulez par exemple charger des propriétés par lazyload. Il s'agit principalement d'un exemple qui, nous l'espérons, explique comment / pourquoi vous pourriez avoir ce problème, afin que vous puissiez prendre des décisions en conséquence
la source
ToList
ingérez mille objets, cela augmentera la mémoire d'une tonne. Dans cet exemple spécifique, vous feriez mieux de combiner la requête interne avec la première afin qu'une seule requête soit générée plutôt que deux.Il existe une autre façon de surmonter ce problème. Que ce soit une meilleure façon dépend de votre situation.
Le problème résulte du chargement paresseux, donc une façon de l'éviter est de ne pas avoir de chargement paresseux, en utilisant Include:
Si vous utilisez les
Include
s appropriés , vous pouvez éviter d'activer MARS. Mais si vous en manquez, vous obtiendrez l'erreur, donc l'activation de MARS est probablement le moyen le plus simple de le corriger.la source
.Include
est une bien meilleure solution que l'activation de MARS, et beaucoup plus facile que d'écrire votre propre code de requête SQL.Vous obtenez cette erreur, lorsque la collection que vous essayez d'itérer est une sorte de chargement paresseux (IQueriable).
La conversion de la collection IQueriable en une autre collection énumérable résoudra ce problème. exemple
Remarque: .ToList () crée à chaque fois un nouvel ensemble et cela peut entraîner des problèmes de performances si vous traitez des données volumineuses.
la source
SELECT COUNT(*) FROM Users
= 5J'ai résolu le problème facilement (pragmatique) en ajoutant l'option au constructeur. Ainsi, je l'utilise uniquement en cas de besoin.
la source
Essayez de définir votre chaîne de connexion
MultipleActiveResultSets=true
. Cela permet le multitâche sur la base de données.Cela fonctionne pour moi ... que votre connexion dans app.config ou que vous la définissiez par programme ... j'espère que cela vous sera utile
la source
J'avais initialement décidé d'utiliser un champ statique dans ma classe API pour référencer une instance de l'objet MyDataContext (où MyDataContext est un objet de contexte EF5), mais c'est ce qui semblait créer le problème. J'ai ajouté du code semblable à ce qui suit à chacune de mes méthodes API et cela a résolu le problème.
Comme d'autres personnes l'ont déclaré, les objets EF Data Context ne sont PAS thread-safe. Donc, les placer dans l'objet statique finira par provoquer l'erreur "lecteur de données" dans les bonnes conditions.
Mon hypothèse initiale était que la création d'une seule instance de l'objet serait plus efficace et permettrait une meilleure gestion de la mémoire. D'après ce que j'ai rassemblé en recherchant cette question, ce n'est pas le cas. En fait, il semble plus efficace de traiter chaque appel à votre API comme un événement isolé et sûr pour les threads. Veiller à ce que toutes les ressources soient correctement libérées, car l'objet est hors de portée.
Cela a du sens, surtout si vous amenez votre API à la prochaine progression naturelle qui serait de l'exposer en tant que WebService ou API REST.
Divulgation
la source
J'ai remarqué que cette erreur se produit lorsque j'envoie un IQueriable à la vue et que je l'utilise dans une double foreach, où la foreach intérieure doit également utiliser la connexion. Exemple simple (ViewBag.parents peut être IQueriable ou DbSet):
La solution simple est d'utiliser
.ToList()
sur la collection avant de l'utiliser. Notez également que MARS ne fonctionne pas avec MySQL.la source
ToList()
sur mon premier appel pour obtenir une collection de la base de données. Ensuite, j'ai fait unforeach
sur cette liste et les appels suivants ont parfaitement fonctionné au lieu de donner l'erreur.J'ai constaté que j'avais la même erreur, et cela s'est produit lorsque j'utilisais un
Func<TEntity, bool>
au lieu d'unExpression<Func<TEntity, bool>>
pour votrepredicate
.Une fois que je l' ai changé toutes
Func's
àExpression's
l'exception cessé d' être jeté.Je crois que cela
EntityFramwork
fait des choses intelligentes avecExpression's
lesquelles il ne fait tout simplement pasFunc's
la source
(MyTParent model, Func<MyTChildren, bool> func)
pour que mes ViewModels puissent spécifier une certainewhere
clause à la méthode Generic DataContext. Rien ne fonctionnait jusqu'à ce que je fasse cela.2 solutions pour atténuer ce problème:
.ToList()
après votre requête, afin que vous puissiez ensuite itérer à travers elle en ouvrant un nouveau DataReader..Include
(/ entités supplémentaires que vous souhaitez charger dans la requête /) cela s'appelle un chargement enthousiaste, qui vous permet (en effet) d'inclure des objets (entités) associés lors de l'exécution d'une requête avec le DataReader.la source
Un bon compromis entre l'activation de MARS et la récupération de l'ensemble des résultats en mémoire consiste à récupérer uniquement les ID dans une requête initiale, puis à parcourir les ID matérialisant chaque entité au fur et à mesure.
Par exemple (en utilisant les exemples d'entités "Blog et publications" comme dans cette réponse ):
Cela signifie que vous ne tirez que quelques milliers d'entiers en mémoire, par opposition à des milliers de graphiques d'objets entiers, ce qui devrait minimiser l'utilisation de la mémoire tout en vous permettant de travailler élément par élément sans activer MARS.
Un autre avantage intéressant de cela, comme le montre l'exemple, est que vous pouvez enregistrer les modifications en parcourant chaque élément, au lieu d'avoir à attendre la fin de la boucle (ou une autre solution de rechange), comme cela serait nécessaire même avec MARS activé (voir ici et ici ).
la source
context.SaveChanges();
à l'intérieur de la boucle :(. Ce n'est pas bon. il doit être à l'extérieur de la boucle.Dans mon cas, j'ai constaté qu'il manquait des instructions "en attente" avant les appels à myContext.SaveChangesAsync (). L'ajout de l'attente avant ces appels asynchrones a résolu les problèmes de lecteur de données pour moi.
la source
Si nous essayons de regrouper une partie de nos conditions dans une méthode d'extension Func <>, nous obtiendrons cette erreur, supposons que nous ayons un code comme celui-ci:
Cela lèvera l'exception si nous essayons de l'utiliser dans un Where (), ce que nous devrions faire à la place est de construire un prédicat comme ceci:
Plus d'informations peuvent être lues sur: http://www.albahari.com/nutshell/predicatebuilder.aspx
la source
Ce problème peut être résolu simplement en convertissant les données en liste
la source
Dans ma situation, le problème s'est produit en raison d'un enregistrement d'injection de dépendance. J'injectais un service d'étendue par demande qui utilisait un dbcontext dans un service enregistré singleton. Par conséquent, le dbcontext a été utilisé dans plusieurs requêtes et donc l'erreur.
la source
Dans mon cas, le problème n'avait rien à voir avec la chaîne de connexion MARS mais avec la sérialisation json. Après avoir mis à niveau mon projet de NetCore2 vers 3, j'ai eu cette erreur.
Plus d'informations peuvent être trouvées ici
la source
J'ai résolu ce problème en utilisant la section de code suivante avant la deuxième requête:
vous pouvez changer l'heure du sommeil en millisecondes
PD Utile lors de l'utilisation de threads
la source