已经有与此命令关联的打开的DataReader,必须首先关闭


640

我有此查询,并且出现此函数错误:

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

Answers:


1286

如果在迭代另一个查询的结果时执行查询,则会发生这种情况。从您的示例尚不清楚发生这种情况的位置,因为该示例尚未完成。

导致这种情况的一件事是,在迭代某些查询的结果时触发了延迟加载。

通过允许在连接字符串中使用MARS可以轻松解决此问题。将MultipleActiveResultSets=true连接字符串添加到提供程序部分(在其中指定了数据源,初始目录等)。


34
这对我有用。如果要阅读有关启用多个活动结果集(MARS)的更多信息,请参见msdn.microsoft.com/en-us/library/h32h3abf(v=vs.100).aspx。考虑也阅读有关火星的缺点的信息stackoverflow.com/questions/374444/…–
Diganta Kumar

3
考虑到性能,您还可以通过包含System.Data.Entity然后使用Include语句来确保在原始查询中加载此辅助数据来解决此问题。如果启用了MARS,则将其关闭以检查是否有重复的数据加载可以通过减少往返行程来帮助加快数据处理调用。
克里斯·莫斯基尼

70
启用MARS仅应针对问题/用例的很小一部分进行。在大多数情况下,有问题的错误是由调用应用程序中的错误代码引起的。此处有更多详细信息:devproconnections.com/development/…–
Michael K. Campbell

132
在your.Include()。Where()之后添加.ToList()可能会解决此问题。
Serj Sagan

2
要进行全局SQL连接,对一个查询进行广泛的更改是荒谬的。正确的答案应该是下面的ToList。针对本地化问题的本地修复程序(即,仅更改查询)!
bytedev '16

218

您可以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;
    }

9
我已经有很多次这个错误了……而每一次我都忘记了!该问题的答案始终是使用ToList()。
Cheesus Toast

1
这有什么缺点吗?如果您有10万行,我怀疑这会很好。
Martin Dawson

2
@MartinMazzaDawson,您真的需要一次执行10万条记录吗?我认为,在这种情况下使用分页是个好主意
kazem 2013年

不好意思提出一个旧主题,但是在开发RepositoryPattern时遇到了相同的错误,我通过在存储库的每个方法中添加“ .ToList()或Single()或Count()”来解决了这个问题。在开始的时候,我只是返回“ .AsEnumerable()”。现在我的问题是:存储库是否应返回“ ToList()”,还是应该向最终使用者
请求保留的

为我工作。添加.ToList解决了JetEntityFrameworkProvider中的十进制支持问题。Total = storeDb.OF_Carts.Where(x => x.CartId == ShoppingCartId).ToList().Sum(t => t.Quantity * t.Item.UnitPrice);
hubert17

39

使用语法.ToList()将从db读取的对象转换为list以避免再次被读取。希望这一点适用。谢谢。


22

这是需要参考的人的有效连接字符串。

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

15
启用MARS是一种解决方法,而不是问题的解决方案。
SandRock

5
在“ MARS文档”页面上:“ MARS操作不是线程安全的。” 这意味着,如果问题是由于访问上下文的多个线程引起的,则MARS(可能)不是解决方案。
marsop

20

就我而言,使用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);
            }
        }
    }
}

如果您的应用程序不需要MARS,则这是最佳解决方案。
Fred Wilson

7

我不知道这是否是重复的答案。如果是我很抱歉。我只想让有需要的人知道如何使用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
}

5

看来您正在使用相同的EF上下文从活动查询中调用DateLastUpdated,并且DateLastUpdate向数据存储本身发出命令。实体框架一次仅在每个上下文中支持一个活动命令。

您可以将上述两个查询重构为一个这样的查询:

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之类的函数。除非这些已存储的proc或函数已从数据库导入到实体数据模型并正确映射,否则它们也会抛出异常,因为EF不知道如何将这些函数转换为可发送到数据存储的语句。

另请注意,调用AsEnumerable不会强制执行查询。直到查询执行推迟到枚举为止。如果需要,可以使用ToList或ToArray强制进行枚举。


如果需要,您可以重构要执行的查询,以将DateLastUpdated直接输入到Accounts Report查询的Select投影中,并获得期望的效果而不会出现错误。
詹姆斯·亚历山大

将函数代码放入主查询后,出现了同样的错误
DotnetSparrow

2

除了Ladislav Mrnka的答案:

如果要在“设置”选项卡上发布和覆盖容器,则可以将MultipleActiveResultSet设置 为True。您可以通过单击“ 高级...”找到该选项,它将位于“ 高级”组下。


2

对于那些通过Google找到的信息;
我收到此错误的原因是,如错误所建议,在同一个SqlCommand上创建另一个之前,我未能关闭SqlDataReader,错误地假定在离开创建方法时会对其进行垃圾回收。

sqlDataReader.Close();在创建第二个阅读器之前,我通过致电解决了这个问题。


2

就我而言,我从数据上下文中打开了一个查询,例如

    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读取的只读属性。


1

当我尝试在读取循环中更新某些记录时,我遇到了相同的错误。我尝试了投票最多的答案MultipleActiveResultSets=true,发现这只是解决下一个错误的解决方法 

不允许新事务,因为会话中有其他线程在运行

最好的方法(适用于巨大的ResultSet)是使用块并为每个块打开单独的上下文,如Entity Framework中的SqlException中所述  -不允许新事务,因为会话中正在运行其他线程


1

我通过更改await _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操作尚未准备好。


1

对我来说,这是我自己的错误。我本应该INSERT使用SqlCommand.executeReader()时正在尝试使用SqlCommand.ExecuteNonQuery()。它是打开的,并且从未关闭过,从而导致错误。注意这种疏忽。


在我这边也是同样的问题。我需要SqlCommand.executeReader(),因为我正在获取插入行ID。所以:我用了SqlDataReader.Close();。SQL Command.Dispose(); 感谢@Andrew Taylor
Fuat

1

这是从一个真实的场景中提取的:

  • 代码在舞台环境中运行良好,并且在连接字符串中设置了MultipleActiveResultSets
  • 在没有MultipleActiveResultSets = true的情况下将代码发布到生产环境
  • 如此多的页面/通话有效,而单个页面/通话失败
  • 仔细查看该调用,对数据库进行了不必要的调用,需要将其删除
  • 在生产环境中设置MultipleActiveResultSets = true并发布清理后的代码,一切正常且高效

总而言之,在不忘记MultipleActiveResultSets的情况下,代码可能已经运行了很长时间,之后才发现可能非常昂贵的冗余db调用,我建议不要完全依赖于设置MultipleActiveResultSets属性,而还要找出为什么代码需要它失败了


1

由于Entity Framework的“延迟加载”功能,很可能发生此问题。通常,除非在初始获取期间明确要求,否则仅在需要时才获取所有联接的数据(存储在其他数据库表中的所有数据)。在许多情况下,这是一件好事,因为它可以防止获取不必要的数据,从而提高查询性能(无联接)并节省带宽。

在问题描述的情况下,将执行初始提取,并且在“选择”阶段中,将请求缺少延迟加载数据的请求,发出其他查询,然后EF抱怨“打开DataReader”。

接受的答案中提出的解决方法将允许执行这些查询,并且实际上整个请求将成功。

但是,如果您要检查发送到数据库的请求,则会注意到多个请求-每个丢失(延迟加载)数据的附加请求。这可能是性能杀手。

更好的方法是告诉EF在初始查询期间预加载所有需要的延迟加载数据。可以使用“包含”语句来完成:

using System.Data.Entity;

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

这样,将执行所有需要的联接,并且所有需要的数据将作为单个查询返回。问题中描述的问题将得到解决。


这是一个有效的答案,因为我从使用Include转到使用EntityEntry.Collection()。Load(),而我的解决方案从正常运行变为崩溃。不幸的是,一个泛型的include不能“ ThenInclude”另一个泛型,因此我仍在尝试使EntityEntry.Collection()。Load()工作。
AndrewBenjamin

0

我在工具中使用Web服务,这些服务在其中获取存储过程。当越来越多的客户端工具获取Web服务时,就会出现此问题。我已通过为那些函数指定同步属性来访存存储过程来进行修复。现在它工作正常,该错误从未出现在我的工具中。

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

此属性允许一次处理一个请求。这样就解决了问题。


0

附带说明...当SQL对象的(内部)数据映射出现问题时,也会发生这种情况。

例如...

我创建了一个SQL Scalar Function,它意外地返回了VARCHAR...,然后将其用于在中生成一列VIEW。将VIEW正确映射到DbContext...所以LINQ的是调用它就好了。但是,实体期望DateTime吗?并且VIEW正在返回String

哪个会抛出...

“已经有与此命令关联的打开的DataReader,必须首先关闭”

很难弄清楚...但是在我更正了返回参数之后...一切都很好


0

就我而言,我不得不设置MultipleActiveResultSetsTrue连接的字符串中。
然后又出现了另一个错误(真正的错误):无法在同一数据上下文中同时运行2(SQL)命令!(EF核心,代码优先)
所以对我来说,解决方案是寻找其他任何异步命令执行,并将它们转换为同步,因为我两个命令都只有一个DbContext。

希望对您有帮助

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.