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

时间:2011-05-19 17:01:47

标签: c# entity-framework entity-framework-4

我有这个查询,我在这个函数中得到错误:

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 个答案:

答案 0 :(得分:1138)

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

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

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

答案 1 :(得分:193)

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

答案 2 :(得分:22)

使用语法.ToList()将从db读取的对象转换为list以避免再次重新读取。希望这对它有效。感谢。

答案 3 :(得分:18)

这是一个需要参考的人的工作连接字符串。

  <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 :(得分:16)

在我的情况下,使用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 :(得分: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
}

答案 6 :(得分:4)

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

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

答案 7 :(得分:2)

除了 Ladislav Mrnka的回答:

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

答案 8 :(得分: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读取的只读属性。

答案 9 :(得分:1)

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

  

不允许使用新事务,因为还有其他线程正在运行   在会议中

适用于大型ResultSet的最佳方法是使用块并为每个块打开单独的上下文,如 SqlException from Entity Framework - New transaction is not allowed because there are other threads running in the session

答案 10 :(得分:1)

我通过改变解决了这个问题 等待_accountSessionDataModel.SaveChangesAsync(); 至 _accountSessionDataModel.SaveChanges(); 在我的Repository类中。

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

问题是我在创建会话后(在代码中)更新了前端中的Sessions,但由于SaveChangesAsync是异步发生的,因此提取会话会导致此错误,因为显然SaveChangesAsync操作尚未就绪。

答案 11 :(得分:1)

对于那些通过谷歌发现的人;
我收到此错误是因为,正如错误所示,我在同一个SqlCommand上创建另一个之前未能关闭SqlDataReader,错误地认为在离开创建它的方法时它将被垃圾收集。

我在创建第二个阅读器之前调用sqlDataReader.Close();解决了这个问题。

答案 12 :(得分:1)

这个问题最有可能是因为&#34;延迟加载&#34;实体框架的特征。通常,除非在初始提取期间明确要求,否则仅在需要时提取所有连接的数据(存储在其他数据库表中的任何内容)。在许多情况下,这是一件好事,因为它可以防止获取不必要的数据,从而提高查询性能(无连接)并节省带宽。

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

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

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

更好的方法是告诉EF在初始查询期间预加载所有需要的延迟加载数据。这可以使用&#34; Include&#34;语句:

using System.Data.Entity;

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

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

答案 13 :(得分:0)

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

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

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

答案 14 :(得分:0)

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

答案 15 :(得分:0)

这是从现实世界的场景中提取的:

  • Code在舞台环境中运行良好,在连接字符串
  • 中设置了MultipleActiveResultSets
  • 在没有MultipleActiveResultSets = true的情况下发布到生产环境的代码
  • 当一个页面/调用失败时,有很多页面/调用正常工作
  • 仔细看看这个电话,对数据库做了 不必要的电话 ,需要删除
  • 在制作中设置MultipleActiveResultSets = true并发布已清理的代码,一切正常且有效

总之,在不忘记MultipleActiveResultSets的情况下,代码可能已经运行了很长时间才发现冗余的db调用,这可能非常昂贵,我建议不要完全依赖于设置MultipleActiveResultSets属性而是 < em>找出代码在失败的地方需要的原因

答案 16 :(得分:0)

作为旁注...当SQL对象的(内部)数据映射出现问题时,也会发生这种情况。

例如...

我创建了一个SQL Scalar Function,它偶然地 返回了VARCHAR ...然后...用来在VIEW中生成一列。 VIEW已正确映射到DbContext ...因此, Linq 称它很好。但是,实体期望 DateTime?,并且VIEW返回字符串

奇怪的是...

  

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

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

答案 17 :(得分:0)

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

希望对您有帮助