С этой командой уже связан открытый DataReader, который должен быть закрыт первым

у меня есть этот запрос, и я получаю ошибку в этой функции:

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();
}

ошибка:

С этой командой уже связан открытый DataReader, который должен быть закрыт первым.

обновление:

трассировка стека добавлено:

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 ответов


Это может произойти, если вы выполняете запрос во время итерации по результатам другого запроса. Из вашего примера неясно, где это происходит, потому что пример не является полным.

одна вещь, которая может вызвать это отложенной загрузки запускаются при переборе результатов запроса.

Это можно легко решить, разрешив MARS в строке подключения. Добавить MultipleActiveResultSets=true к поставщику часть строки подключения (где источник данных, исходный каталог, так далее. указываются).


можно использовать ToList() способ перед 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;
    }

вот рабочая строка подключения для тех, кто нуждается в ссылке.

  <connectionStrings>
    <add name="IdentityConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\IdentityDb.mdf;Integrated Security=True;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient" />
  </connectionStrings>

в моем случае, используя Include() решил эту ошибку и в зависимости от ситуации может быть намного эффективнее, чем выдача нескольких запросов, когда все это можно запросить сразу с помощью соединения.

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);
            }
        }
    }
}

использовать следующий синтаксис:.ToList() для преобразования объекта чтения из БД в список, чтобы избежать повторного чтения.Надеюсь, это сработает. Спасибо.


Я не знаю, является ли это дублирующим ответом или нет. Если это так, мне очень жаль. Я просто хочу, чтобы нуждающиеся знали, как я решил свою проблему с помощью ToList().

в моем случае я получил такое же исключение для приведенного ниже запроса.

int id = adjustmentContext.InformationRequestOrderLinks.Where(item => item.OrderNumber == irOrderLinkVO.OrderNumber && item.InformationRequestId == irOrderLinkVO.InformationRequestId).Max(item => item.Id);

Я решил, как ниже

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
}

похоже, что вы вызываете DateLastUpdated из активного запроса, используя тот же контекст EF, и DateLastUpdate выдает команду самому хранилищу данных. Entity Framework поддерживает только одну активную команду на контекст за раз.

вы можете разложить ваши выше двух запросов в один, как этот:

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);

Я также заметил, что вы вызываете такие функции, как FormattedAccountNumber и FormattedRecordNumber в запросах. Если они не хранятся procs или функции, которые вы импортировали из своей базы данных в модель данных сущности и сопоставили правильно, они также будут вызывать исключения, поскольку EF не будет знать, как перевести эти функции в операторы, которые он может отправить в хранилище данных.

также обратите внимание, что вызов AsEnumerable не заставляет запрос выполняться. Пока выполнение запроса не будет отложено до перечисления. Вы можете принудительно перечислить с ToList или ToArray, если хотите.


кроме Ладислав Mrnka это ответ:

Если вы публикуете и переопределяете контейнер на настройки tab, вы можете установить MultipleActiveResultSet значение true. Вы можете найти эту опцию, нажав дополнительно... и будет в дополнительно группы.


У меня была такая же ошибка, когда я пытался обновить некоторые записи в цикле чтения. Я пробовал самый проголосовавший ответ MultipleActiveResultSets=true и обнаружил, что это просто обходной путь, чтобы получить следующий ошибка

новая транзакция не разрешена, потому что работают другие потоки в сессии

лучший подход, который будет работать для огромных наборов результатов, - использовать фрагменты и открывать отдельный контекст для каждого фрагмента, как описано в  SqlException от сущности Framework-новая транзакция не разрешена, потому что в сеансе работают другие потоки


Я решил эту проблему путем изменения жду _аккунтсессиондатамодель.SaveChangesAsync(); к _accountSessionDataModel.Метод SaveChanges(); в моем классе репозитория.

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

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

изменил его на:

 public Session CreateSession()
    {
        var session = new Session();

        _accountSessionDataModel.Sessions.Add(session);
        _accountSessionDataModel.SaveChanges();
     }

проблема заключалась в том, что я обновил сеансы в интерфейсе после создания сеанса (в коде), но поскольку SaveChangesAsync происходит асинхронно, извлечение сеансов вызвало эту ошибку, потому что, по-видимому, операция SaveChangesAsync еще не была готова.


для тех, кто находит это через Google;
Я получал эту ошибку, потому что, как было предложено ошибкой, мне не удалось закрыть SqlDataReader до создания другого на той же SqlCommand, ошибочно полагая, что это будет мусор, собранный при выходе из метода, в котором он был создан.

Я решил проблему путем вызова sqlDataReader.Close(); перед созданием второго считывателя.


в моем случае, я открыл запрос из контекста данных, как

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

... а потом задал тот же вопрос...

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

добавлять .ToList чтобы первый решил мою проблему. Я думаю, имеет смысл обернуть это в свойство, как:

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

где _stores-это частная переменная, а Filters-также свойство readonly, которое считывает из AppSettings.


Я использую веб-службу в своем инструменте, где эти службы извлекают хранимую процедуру. в то время как большее количество клиентских инструментов извлекает веб-службу, эта проблема возникает. Я исправил, указав синхронизированный атрибут для тех функций, которые извлекают хранимую процедуру. теперь он работает нормально, ошибка никогда не появлялась в моем инструменте.

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

этот атрибут позволяет обрабатывать один запрос за раз. это решает проблему.


Ну для меня это была моя собственная ошибка. Я пытался запустить INSERT используя SqlCommand.executeReader() когда я должен был с помощью SqlCommand.ExecuteNonQuery(). Он был открыт и никогда не закрывался, вызывая ошибку. Остерегайтесь этой оплошности.


Это извлекается из сценария реального мира:

  • код хорошо работает в среде этапа с MultipleActiveResultSets устанавливается в строке подключения
  • код, опубликованный в производственной среде без MultipleActiveResultSets=true
  • так много страниц / вызовов работают, пока один из них терпит неудачу
  • глядя ближе на вызов, есть ненужный вызов сделано в БД и должно быть удалено
  • Set MultipleActiveResultSets=true в производстве и публикации очищенного кода, все работает хорошо и эффективно

В заключение, не забывая о MultipleActiveResultSets, код может работать в течение длительного времени, прежде чем обнаружить избыточный вызов БД, который может быть очень дорогостоящим, и я предлагаю не полностью зависеть от установки атрибута MultipleActiveResultSets, но также узнайте, почему код нуждается в нем, где он не удалось.


скорее всего, эта проблема возникает из-за функции" ленивой загрузки " Entity Framework. Обычно, если явно не требуется во время начальной выборки, все объединенные данные (все, что хранится в других таблицах базы данных) извлекаются только при необходимости. Во многих случаях это хорошо, так как это предотвращает получение ненужных данных и, таким образом, улучшает производительность запросов (без соединений) и экономит пропускную способность.

в ситуации, описанной в вопросе, выполняется начальная выборка, и во время фазы" select "запрашиваются отсутствующие данные ленивой загрузки, выдаются дополнительные запросы, а затем EF жалуется на"open DataReader".

обходной путь, предложенный в принятом ответе, позволит выполнить эти запросы, и действительно, весь запрос будет успешным.

однако, если вы изучите запросы, отправленные в базу данных, вы заметите несколько запросов-дополнительный запрос для каждой отсутствующей (ленивой загрузки) данных. Это может быть представление убийца.

лучший подход-сказать EF, чтобы предварительно загрузить все необходимые ленивые загруженные данные во время начального запроса. Это можно сделать с помощью оператора" Include":

using System.Data.Entity;

query = query.Include(a => a.LazyLoadedProperty);

таким образом, все необходимые соединения будут выполнены и все необходимые данные будут возвращены как один запрос. Проблема, описанная в вопросе, будет решена.