Уже есть открытый 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, связанный с этой Командой, который должен быть закрыт первым.

Update:

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

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

Ответ 1

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

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

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

Ответ 2

Вы можете использовать метод 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;
    }

Ответ 3

Вот рабочая строка для тех, кому нужна ссылка.

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

Ответ 4

В моем случае использование 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);
            }
        }
    }
}

Ответ 5

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

Ответ 6

Я не знаю, является ли это дублирующим ответом или нет. Если мне жаль. Я просто хочу, чтобы нуждающиеся знали, как я решил свою проблему, используя 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
}

Ответ 7

Похоже, вы вызываете 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. Если они не сохранены в процедурах или функциях, которые вы импортировали из своей базы данных в модель данных сущности и правильно настроены, они также будут выдавать исключения, поскольку EF не будет знать, как перевести эти функции в операторы, которые он может отправить в хранилище данных.

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

Ответ 8

В дополнение к ответу Ladislav Mrnka:

Если вы публикуете и переопределяете контейнер на вкладке "Настройки", вы можете установить для параметра MultipleActiveResultSet значение "Истина". Вы можете найти этот параметр, нажав "Дополнительно"... и он будет находиться в группе "Дополнительно".

Ответ 9

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

Новая транзакция не допускается, так как существуют другие потоки в сеансе

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

Ответ 10

Я решил эту проблему, изменив wait_accountSessionDataModel.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 еще не была готова.

Ответ 11

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

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

Ответ 12

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

    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.

Ответ 13

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

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

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

Ответ 14

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

Ответ 15

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

  • Код работает хорошо в среде Stage с MultipleActiveResultSets устанавливается в строке подключения
  • Код, опубликованный в производственной среде без MultipleActiveResultSets = true
  • Так много страниц/звонков работают, пока один не работает
  • Приближаясь к вызову, есть ненужный вызов, сделанный в db, и его необходимо удалить.
  • Установить MultipleActiveResultSets = true в Production и опубликовать очищенный код, все работает хорошо и эффективно

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

Ответ 16

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

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

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

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

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

using System.Data.Entity;

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

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