web-dev-qa-db-fra.com

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. 

Mettre à 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 Work\SuperExpert\CreditRegistry\CreditRegistry\Repositories\CreditRegistryRepository.cs:1497
   CreditRegistry.Repositories.CreditRegistryRepository.<AccountDetails>b__88(AccountsReport account, Int32 index) in D:\Freelance Work\SuperExpert\CreditRegistry\CreditRegistry\Repositories\CreditRegistryRepository.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
522
DotnetSparrow

Cela peut arriver si vous exécutez une requête en itérant les résultats d'une autre requête. Dans votre exemple, il n’est pas clair où cela se produit car cet exemple n’est pas complet.

Une chose qui peut causer ceci est un chargement paresseux déclenché lors d'une 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ù la source de données, le catalogue initial, etc. sont spécifiés).

1102
Ladislav Mrnka

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;
    }
186
kazem

utilisez la syntaxe .ToList() pour convertir l'objet lu de la base de données à la liste afin d'éviter d'être relu.Il espère que cela fonctionnerait. Merci.

18
Icemark Muturi

Voici une chaîne de connexion qui fonctionne pour quelqu'un qui a besoin d'une 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>
16
Yang Zhang

Dans mon cas, utiliser Include() a résolu cette erreur et, selon la situation, peut s'avérer beaucoup plus efficace que d'émettre plusieurs requêtes lorsque tout peut être interrogé simultanément 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);
            }
        }
    }
}
15
Despertar

Je ne sais pas s'il s'agit d'une réponse en double ou non. Si c'est le cas, je suis désolé. Je veux simplement faire savoir aux nécessiteux 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
}
7
Ziggler

Il semble que vous appeliez DateLastUpdated à partir d'une requête active utilisant le même contexte EF et que 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 reformuler 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 telles que FormattedAccountNumber et FormattedRecordNumber dans les requêtes. À moins qu'il s'agisse de procédures ou de fonctions stockées que vous avez importées de votre base de données dans le modèle de données d'entité et mappées correctement, elles seront également rejetées, car EF ne saura pas comment traduire ces fonctions en instructions à envoyer au magasin de données. 

Notez également qu'appeler 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'à énumération. Vous pouvez forcer l'énumération avec ToList ou ToArray si vous le souhaitez.

4
James Alexander

En plus de Ladislav Mrnka's answer:

Si vous publiez et substituez le conteneur sur l'onglet {Paramètres}, vous pouvez définir MultipleActiveResultSet sur True. Vous pouvez trouver cette option en cliquant sur Avancé ... et il se trouvera sous le groupe Avancé

2

Dans mon cas, j'avais ouvert une requête à partir d'un contexte de données, comme

    Dim stores = DataContext.Stores _
        .Where(Function(d) filter.Contains(d.code)) _

... et ensuite interrogé le même ...

    Dim stores = DataContext.Stores _
        .Where(Function(d) filter.Contains(d.code)).ToList

L'ajout du .ToList au premier problème résolu. 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 de AppSettings.

2
Adam Cox

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 j'ai trouvé que c'était 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 d’énormes ResultSets, consiste à utiliser des fragments et à ouvrir un contexte séparé pour chaque fragment, comme décrit dans Exception SQL d’Entity Framework - Une nouvelle transaction n’est pas autorisée car d’autres threads sont en cours d’exécution dans la session .

1

Pour ceux qui trouvent cela via Google;
J'avais eu cette erreur parce que, comme suggéré par l'erreur, je n'ai pas réussi à fermer un SqlDataReader avant d'en créer un autre sur le même SqlCommand, en supposant à tort qu'il s'agirait d'ordures récupérées en quittant la méthode dans laquelle il avait été créé 

J'ai résolu le problème en appelant sqlDataReader.Close(); avant de créer le deuxième lecteur.

1
timelmer

J'ai résolu ce problème en changeant Wait _accountSessionDataModel.SaveChangesAsync (); En _ accountSessionDataModel.SaveChanges (); Dans ma classe Repository.

 public async Task<Session> CreateSession()
    {
        var session = new Session();

        _accountSessionDataModel.Sessions.Add(session);
        await _accountSessionDataModel.SaveChangesAsync();
     }

Changé pour:

 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 l'interface après la création d'une session (dans le code), mais parce que SaveChangesAsync se produit de manière asynchrone, l'extraction des sessions a provoqué cette erreur car apparemment l'opération SaveChangesAsync n'était pas prête.

1
woutercx

Très probablement, ce problème se produit en raison de la fonctionnalité de "chargement paresseux" de Entity Framework. En général, sauf si cela est 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 extraites que lorsque cela est nécessaire. Dans de nombreux cas, c'est une bonne chose, car cela évite d'extraire des données inutiles et donc d'améliorer les performances des requêtes (pas de jointures) et d'économiser de la bande passante.

Dans la situation décrite dans la question, la récupération initiale est effectuée et, lors de la phase "sélection", des données de chargement différé manquantes sont demandées, des requêtes supplémentaires sont émises, puis EF se plaint de "données ouvertes".

La solution de contournement proposée dans la réponse acceptée permettra l'exécution de ces requêtes et la requête dans son ensemble aboutira.

Toutefois, si vous examinez les demandes envoyées à la base de données, vous remarquerez plusieurs demandes - une demande supplémentaire pour chaque donnée manquante (chargée paresseuse). Cela pourrait être un tueur de performance.

Une meilleure approche consiste à dire à EF de précharger toutes les données nécessaires chargées paresseux au cours de 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 renvoyées sous la forme d'une requête unique. Le problème décrit dans la question sera résolu.

1
Illidan

J'utilise un service Web dans mon outil, où ce service récupère la procédure stockée. Bien que plus d’utilisateurs client récupèrent le service Web, ce problème se pose. J'ai corrigé en spécifiant l'attribut Synchronized pour que cette fonction récupère la procédure stockée. maintenant cela fonctionne bien, l'erreur n'a jamais été détectée dans mon outil.

 [MethodImpl(MethodImplOptions.Synchronized)]
 public static List<t> MyDBFunction(string parameter1)
  {
  }

Cet attribut permet de traiter une requête à la fois. donc cela résout le problème. 

0
Pranesh Janarthanan

Dans mon cas, je devais définir MultipleActiveResultSets sur True dans la chaîne de connexion.
Ensuite, il est apparu une autre erreur (la vraie) sur l'impossibilité d'exécuter 2 commandes (SQL) en même temps sur le même contexte de données! (EF Core, code d'abord)
La solution pour moi était donc de rechercher toute autre exécution de commande asynchrone et de la transformer en synchrone , car je n'avais qu'un DbContext pour les deux commandes.

J'espère que ça t'aide

0
Dr TJ

Eh bien pour moi, c'était mon propre bug. J'essayais de lancer une INSERT en utilisant SqlCommand.executeReader() alors que j'aurais dû utiliser SqlCommand.ExecuteNonQuery(). Il a été ouvert et jamais fermé, provoquant l'erreur. Attention à cet oubli.

0
Andrew Taylor

Cela peut aussi arriver en cas de problème avec le mappage de données (interne) à partir d'objets SQL.

Par exemple...

J'ai créé un SQL Scalar Function qui accidentellement a retourné une VARCHAR... et l'a ensuite utilisé pour générer une colonne dans une VIEW. La VIEW a été correctement cartographiée dans la DbContext... donc Linq l'appelait parfaitement. Cependant, l'entité Entity attendue DateTime? et la VIEW retournait String

Qui jette ODDLY ...

"Il existe déjà un DataReader ouvert associé à cette commande Qui doit être fermé en premier"

C'était difficile à comprendre ... mais après avoir corrigé les paramètres de retour ... tout allait bien

0
Prisoner ZERO