Il existe déjà un DataReader ouvert associé à cette commande qui doit être fermé en premier
J'ai cette requête et j'obtiens l'erreur dans cette fonction:
var accounts = from account in context.Accounts
from guranteer in account.Gurantors
select new AccountsReport
{
CreditRegistryId = account.CreditRegistryId,
AccountNumber = account.AccountNo,
DateOpened = account.DateOpened,
};
return accounts.AsEnumerable()
.Select((account, index) => new AccountsReport()
{
RecordNumber = FormattedRowNumber(account, index + 1),
CreditRegistryId = account.CreditRegistryId,
DateLastUpdated = DateLastUpdated(account.CreditRegistryId, account.AccountNumber),
AccountNumber = FormattedAccountNumber(account.AccountType, account.AccountNumber)
})
.OrderBy(c=>c.FormattedRecordNumber)
.ThenByDescending(c => c.StateChangeDate);
public DateTime DateLastUpdated(long creditorRegistryId, string accountNo)
{
return (from h in context.AccountHistory
where h.CreditorRegistryId == creditorRegistryId && h.AccountNo == accountNo
select h.LastUpdated).Max();
}
L'erreur est:
Il existe déjà un DataReader ouvert associé à cette commande qui doit être fermé en premier.
Mise à Jour:
Trace de pile Ajoutée:
InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.]
System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command) +5008639
System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method, SqlCommand command) +23
System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async) +144
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +87
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +32
System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +141
System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) +12
System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior) +10
System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) +443
[EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details.]
System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior) +479
System.Data.Objects.Internal.ObjectQueryExecutionPlan.Execute(ObjectContext context, ObjectParameterCollection parameterValues) +683
System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) +119
System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() +38
System.Linq.Enumerable.Single(IEnumerable`1 source) +114
System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__3(IEnumerable`1 sequence) +4
System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle(IEnumerable`1 query, Expression queryRoot) +29
System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute(Expression expression) +91
System.Data.Entity.Internal.Linq.DbQueryProvider.Execute(Expression expression) +69
System.Linq.Queryable.Max(IQueryable`1 source) +216
CreditRegistry.Repositories.CreditRegistryRepository.DateLastUpdated(Int64 creditorRegistryId, String accountNo) in D:Freelance WorkSuperExpertCreditRegistryCreditRegistryRepositoriesCreditRegistryRepository.cs:1497
CreditRegistry.Repositories.CreditRegistryRepository.<AccountDetails>b__88(AccountsReport account, Int32 index) in D:Freelance WorkSuperExpertCreditRegistryCreditRegistryRepositoriesCreditRegistryRepository.cs:1250
System.Linq.<SelectIterator>d__7`2.MoveNext() +198
System.Linq.Buffer`1..ctor(IEnumerable`1 source) +217
System.Linq.<GetEnumerator>d__0.MoveNext() +96
16 réponses
Cela peut se produire si vous exécutez une requête tout en itérant sur les résultats d'une autre requête. Il n'est pas clair d'après votre exemple où cela se produit parce que l'exemple n'est pas complet.
Une chose qui peut causer ceci est le chargement paresseux déclenché lors de l'itération sur les résultats d'une requête.
Cela peut être facilement résolu en autorisant MARS dans votre chaîne de connexion. Ajoutez MultipleActiveResultSets=true
à la partie fournisseur de votre chaîne de connexion (où source de données, catalogue Initial, etc. être défini).
Vous pouvez utiliser la méthode ToList()
avant l'instruction return
.
var accounts =
from account in context.Accounts
from guranteer in account.Gurantors
select new AccountsReport
{
CreditRegistryId = account.CreditRegistryId,
AccountNumber = account.AccountNo,
DateOpened = account.DateOpened,
};
return accounts.AsEnumerable()
.Select((account, index) => new AccountsReport()
{
RecordNumber = FormattedRowNumber(account, index + 1),
CreditRegistryId = account.CreditRegistryId,
DateLastUpdated = DateLastUpdated(account.CreditRegistryId, account.AccountNumber),
AccountNumber = FormattedAccountNumber(account.AccountType, account.AccountNumber)}).OrderBy(c=>c.FormattedRecordNumber).ThenByDescending(c => c.StateChangeDate).ToList();
public DateTime DateLastUpdated(long creditorRegistryId, string accountNo)
{
var dateReported = (from h in context.AccountHistory
where h.CreditorRegistryId == creditorRegistryId && h.AccountNo == accountNo
select h.LastUpdated).Max();
return dateReported;
}
Voici une chaîne de connexion de travail pour quelqu'un qui a besoin de référence.
<connectionStrings>
<add name="IdentityConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\IdentityDb.mdf;Integrated Security=True;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient" />
</connectionStrings>
Dans mon cas, en utilisant Include()
résolu cette erreur et en fonction de la situation peut être beaucoup plus efficace que d'émettre plusieurs requêtes quand il peut tous être interrogé à la fois avec une jointure.
IEnumerable<User> users = db.Users.Include("Projects.Tasks.Messages");
foreach (User user in users)
{
Console.WriteLine(user.Name);
foreach (Project project in user.Projects)
{
Console.WriteLine("\t"+project.Name);
foreach (Task task in project.Tasks)
{
Console.WriteLine("\t\t" + task.Subject);
foreach (Message message in task.Messages)
{
Console.WriteLine("\t\t\t" + message.Text);
}
}
}
}
Utilisez la syntaxe .ToList()
pour convertir l'objet lu de la base de données en liste afin d'éviter d'être relu à nouveau.J'espère que cela fonctionnerait pour cela. Grâce.
Je ne sais pas si c'est une réponse en double ou non. Si c'est je suis désolé. Je veux juste que les nécessiteux sachent comment j'ai résolu mon problème en utilisant ToList ().
Dans mon cas, j'ai la même exception pour la requête ci-dessous.
int id = adjustmentContext.InformationRequestOrderLinks.Where(item => item.OrderNumber == irOrderLinkVO.OrderNumber && item.InformationRequestId == irOrderLinkVO.InformationRequestId).Max(item => item.Id);
J'ai résolu comme ci-dessous
List<Entities.InformationRequestOrderLink> links = adjustmentContext.InformationRequestOrderLinks
.Where(item => item.OrderNumber == irOrderLinkVO.OrderNumber && item.InformationRequestId == irOrderLinkVO.InformationRequestId).ToList();
int id = 0;
if (links.Any())
{
id = links.Max(x => x.Id);
}
if (id == 0)
{
//do something here
}
Il semble que vous appelez DateLastUpdated à partir d'une requête active utilisant le même contexte EF et DateLastUpdate envoie une commande au magasin de données lui-même. Entity Framework ne prend en charge qu'une seule commande active par contexte à la fois.
Vous pouvez refactoriser vos deux requêtes ci-dessus en une seule comme ceci:
return accounts.AsEnumerable()
.Select((account, index) => new AccountsReport()
{
RecordNumber = FormattedRowNumber(account, index + 1),
CreditRegistryId = account.CreditRegistryId,
DateLastUpdated = (
from h in context.AccountHistory
where h.CreditorRegistryId == creditorRegistryId
&& h.AccountNo == accountNo
select h.LastUpdated).Max(),
AccountNumber = FormattedAccountNumber(account.AccountType, account.AccountNumber)
})
.OrderBy(c=>c.FormattedRecordNumber)
.ThenByDescending(c => c.StateChangeDate);
J'ai également remarqué que vous appelez des fonctions comme FormattedAccountNumber et FormattedRecordNumber dans les requêtes. Sauf si ce sont des procs ou des fonctions stockées que vous avez importé de votre base de données dans le modèle de données d'entité et mappé correctement, ceux-ci lanceront également des exceptions car EF ne saura pas comment traduire ces fonctions en instructions qu'il peut envoyer au magasin de données.
Notez également que l'appel à AsEnumerable ne force pas l'exécution de la requête. Jusqu'à ce que l'exécution de la requête soit différée jusqu'à ce qu'elle soit énumérée. Vous pouvez forcer l'énumération avec ToList ou ToArray si vous le désirez.
En plus de la réponsede Ladislav Mrnka:
Si vous publiez et remplacez le conteneur dans l'onglet Settings , Vous pouvez définir MultipleActiveResultSet sur True. Vous pouvez trouver cette option en cliquant sur avancé... et il va être sous - Avancé groupe.
J'ai eu la même erreur, quand j'ai essayé de mettre à jour certains enregistrements dans la boucle de lecture.
J'ai essayé la réponse la plus votée MultipleActiveResultSets=true
et trouvé, que c'est juste une solution de contournement pour obtenir l'erreur suivante
La nouvelle transaction n'est pas autorisée car d'autres threads sont en cours d'exécution dans la session
La meilleure approche, qui fonctionnera pour les ensembles de résultats énormes est d'utiliser des morceaux et d'ouvrir un contexte séparé pour chaque morceau comme décrit dans SqlException from Entity Framework - la nouvelle transaction est non autorisé car d'autres threads s'exécutent dans la session
, j'ai résolu ce problème en changeant attendre _accountSessionDataModel.SaveChangesAsync(); de _accountSessionDataModel.SaveChanges(); dans ma classe de Référentiel.
public async Task<Session> CreateSession()
{
var session = new Session();
_accountSessionDataModel.Sessions.Add(session);
await _accountSessionDataModel.SaveChangesAsync();
}
L'a changé en:
public Session CreateSession()
{
var session = new Session();
_accountSessionDataModel.Sessions.Add(session);
_accountSessionDataModel.SaveChanges();
}
Le problème était que j'ai mis à jour les Sessions dans le frontend après avoir créé une session (dans le code), mais comme SaveChangesAsync se produit de manière asynchrone, l'extraction des sessions a provoqué cette erreur car apparemment L'opération SaveChangesAsync n'était pas encore prête.
Pour ceux qui trouvent cela via Google;
Je recevais cette erreur parce que, comme suggéré par l'erreur, j'ai échoué à fermer un SqlDataReader avant d'en créer un autre sur le même SqlCommand, en supposant à tort qu'il serait collecté en quittant la méthode dans laquelle il a été créé.
J'ai résolu le problème en appelant sqlDataReader.Close();
avant de créer le deuxième lecteur.
Dans mon cas, j'avais ouvert une requête à partir du contexte de données, comme
Dim stores = DataContext.Stores _
.Where(Function(d) filter.Contains(d.code)) _
... et puis par la suite interrogé le même...
Dim stores = DataContext.Stores _
.Where(Function(d) filter.Contains(d.code)).ToList
L'ajout du .ToList
au premier a résolu mon problème. Je pense qu'il est logique d'envelopper cela dans une propriété comme:
Public ReadOnly Property Stores As List(Of Store)
Get
If _stores Is Nothing Then
_stores = DataContext.Stores _
.Where(Function(d) Filters.Contains(d.code)).ToList
End If
Return _stores
End Get
End Property
Où _stores est une variable privée et Filters est également une propriété en lecture seule qui lit à partir D'AppSettings.
J'utilise le service web dans mon outil, où ces services récupèrent la procédure stockée. alors que plus de nombre d'outils client récupère le service web, ce problème se pose. J'ai corrigé en spécifiant l'attribut synchronisé pour ces fonctions récupère la procédure stockée. maintenant, cela fonctionne bien, l'erreur n'est jamais apparue dans mon outil.
[MethodImpl(MethodImplOptions.Synchronized)]
public static List<t> MyDBFunction(string parameter1)
{
}
Cet attribut permet de traiter une requête à la fois. si cela résout le Problème.
Eh bien pour moi, c'était mon propre bug. J'essayais d'exécuter un INSERT
en utilisant SqlCommand.executeReader()
quand j'aurais dû utiliser SqlCommand.ExecuteNonQuery()
. Il a été ouvert et jamais fermé, provoquant l'erreur. Watch out pour cette surveillance.
Ceci est extrait d'un scénario réel:
- le Code fonctionne bien dans un environnement de scène avec MultipleActiveResultSets est défini dans la chaîne de connexion
- Code publié dans l'environnement de Production sans MultipleActiveResultSets = true
- Tant de pages / appels fonctionnent alors qu'un seul échoue
- en regardant de plus près l'appel, il y a un appel inutile fait à la base de données et doit être supprimé
- Définir MultipleActiveResultSets=true dans la Production et la publication de code nettoyé, tout fonctionne bien et, efficacement
En conclusion, sans oublier MultipleActiveResultSets, le code pourrait avoir fonctionné pendant longtemps avant de découvrir un appel DB redondant qui pourrait être très coûteux, et je suggère de ne pas dépendre entièrement de la définition de L'attribut MultipleActiveResultSets mais aussi découvrez pourquoi le code en a besoin là où il a échoué.
Très probablement ce problème se produit en raison de la fonctionnalité" chargement paresseux " de Entity Framework. Habituellement, à moins d'être explicitement requis lors de l'extraction initiale, toutes les données jointes (tout ce qui est stocké dans d'autres tables de base de données) ne sont récupérées que lorsque cela est nécessaire. Dans de nombreux cas, c'est une bonne chose, car cela empêche d'extraire des données inutiles et améliore ainsi les performances de la requête (Pas de jointures) et économise de la bande passante.
Dans la situation décrite dans la question, l'extraction initiale est effectuée, et pendant phase" select "les données de chargement paresseux manquantes sont demandées, des requêtes supplémentaires sont émises et EF se plaint de "open DataReader".
La solution de contournement proposée dans la réponse acceptée permettra l'exécution de ces requêtes, et en effet toute la requête réussira.
Cependant, si vous examinez les requêtes envoyées à la base de données, vous remarquerez plusieurs requêtes - Requête supplémentaire pour chaque donnée manquante (chargée paresseuse). Cela pourrait être un tueur de performance.
Un meilleur l'approche consiste à dire à EF de précharger toutes les données chargées paresseuses nécessaires pendant la requête initiale. Cela peut être fait en utilisant l'instruction "Include":
using System.Data.Entity;
query = query.Include(a => a.LazyLoadedProperty);
De cette façon, toutes les jointures nécessaires seront effectuées et toutes les données nécessaires seront retournées en tant que requête unique. Le problème décrit dans la question sera résolue.