Уже существует открытый DataReader, связанный с этой командой, который должен быть закрыт первым - PullRequest
565 голосов
/ 19 мая 2011

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

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

Ответы [ 18 ]

1159 голосов
/ 20 мая 2011

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

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

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

201 голосов
/ 14 января 2013

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

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

19 голосов
/ 17 июля 2015

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

  <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 голосов
/ 15 апреля 2013

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

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

Похоже, что вы вызываете 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.

2 голосов
/ 12 марта 2018

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

    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 - также свойство только для чтения, которое читает из AppSettings.

2 голосов
/ 17 октября 2014

В дополнение к ответ Ладислава Мрнки :

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

1 голос
/ 31 марта 2018

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

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

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

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

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

using System.Data.Entity;

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...