已经有一个与此命令关联的打开的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 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
611661 次浏览

似乎您正在使用相同的EF上下文从活动查询中调用DateLastUpdate,并且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);

我还注意到您在查询中调用了FormattedAccountNumberFormattedRecordNumber等函数。除非这些是您从数据库导入到实体数据模型并正确映射的存储过程或函数,否则这些也会抛出异常,因为EF不知道如何将这些函数转换为可以发送到数据存储的语句。

另请注意,调用AsEnumerable不会强制执行查询。直到查询执行推迟到枚举。如果需要,您可以使用ToListToArray强制枚举。

如果您在迭代另一个查询的结果时执行查询,就会发生这种情况。从您的示例中不清楚这种情况发生在哪里,因为示例不完整。

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

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

您可以在return语句之前使用ToList()方法。

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

在我的例子中,使用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()解决我的问题的。

在我的情况下,我对下面的查询有同样的例外。

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
}

除了拉迪斯拉夫·姆恩卡的答案:

如果您在设置选项卡上发布和覆盖容器,您可以将多活动结果集设置为True。您可以通过单击高级…找到此选项,它将位于高级组下。

这是需要引用的人的工作连接字符串。

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

我在我的工具中使用网络服务,这些服务获取存储过程。当更多数量的客户端工具获取网络服务时,出现了这个问题。我已经通过为那些函数指定同步属性来修复获取存储过程。现在它工作正常,错误从未出现在我的工具中。

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

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

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

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

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

使用语法.ToList()将从db读取的对象转换为list,以避免再次被重新读取。

我解决了这个问题 等待_accountSessionDataModel. SaveChangesAsync(); 来 _accountSessionDataModel保存更改(); 在我的存储库类中。

 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操作尚未准备好。

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

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

对我来说,这是我自己的bug。当我应该使用SqlCommand.ExecuteNonQuery()时,我试图使用SqlCommand.executeReader()运行INSERT。它被打开但从未关闭,导致了错误。小心这个疏忽。

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

  • 代码在连接字符串中设置了MultipleActiveResultSets的舞台环境中运行良好
  • 发布到生产环境的代码,没有MultipleActiveResultSets=true
  • 如此多的页面/调用工作,而一个失败
  • 仔细观察调用,有一个不必要的电话对db进行了操作,需要删除
  • 在生产和发布清理代码中设置MultipleActiveResultSets=true,一切都运行良好,高效

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

在我的例子中,我从数据上下文中打开了一个查询,例如

    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也是只读属性,可从AppSetting读取。

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

在问题中描述的情况下,执行初始获取,并在“选择”阶段请求丢失的延迟加载数据,发出额外的查询,然后EF抱怨“打开DataReader”。

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

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

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

using System.Data.Entity;


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

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

顺便说一句…当来自SQL对象的(内部)数据映射出现问题时,也会发生这种情况。

比如说…

我创建了一个SQL Scalar Function意外返回一个VARCHAR…然后…用它在VIEW中生成一列。VIEWDbContext中被正确映射…所以Linq称之为很好。然而,实体预期日期时间?VIEW返回VARCHAR0。

奇怪的是…

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

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

在我的例子中,我必须在连接字符串中设置MultipleActiveResultSetsTrue
然后出现了另一个错误(真正的错误),即无法在相同的数据上下文中同时运行两个(SQL)命令!(EF Core,代码优先)
所以我的解决方案是寻找任何其他异步命令执行并将它们转换为同步,因为我只有一个DbContext用于这两个命令。

希望对你有帮助

当我循环和更新数据时,同样的错误发生在我身上 IEnumerable<MyClass> 当我将循环集合更改为List<MyClass>并通过.ToList()转换来填充它时,它解决并更新了没有任何错误。