已经有一个与此命令关联的打开的 DataReader,必须先关闭它
本文关键字:DataReader 有一个 命令 关联 | 更新日期: 2023-09-27 17:57:17
我有这个查询,我在这个函数中得到错误:
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
如果在循环访问另一个查询的结果时执行查询,则可能会发生这种情况。从您的示例中不清楚发生这种情况的位置,因为示例不完整。
可能导致这种情况的一件事是在迭代某些查询的结果时触发延迟加载。
通过在连接字符串中允许 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;
}
使用语法.ToList()
将读取的对象从 db 转换为列表,以避免再次读取。
下面是需要参考的人的工作连接字符串。
<connectionStrings>
<add name="IdentityConnection" connectionString="Data Source=(LocalDb)'v11.0;AttachDbFilename=|DataDirectory|'IdentityDb.mdf;Integrated Security=True;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient" />
</connectionStrings>
就我而言,使用 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
}
您似乎使用相同的 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);
我还注意到您在查询中调用了 FormattedAccountNumber
和 FormattedRecordNumber
等函数。除非这些是已从数据库导入到实体数据模型中并正确映射的存储过程或函数,否则这些过程或函数也会引发例外情况,因为 EF 不知道如何将这些函数转换为它可以发送到数据存储的语句。
另请注意,调用 AsEnumerable
不会强制执行查询。直到查询执行延迟到枚举。如果需要,可以使用ToList
或ToArray
强制枚举。
就我而言,我从数据上下文中打开了一个查询,例如
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是私有变量,筛选器也是从应用设置读取的只读属性。
作为旁注...当来自 SQL 对象的(内部)数据映射出现问题时,也会发生这种情况。
例如。。。
我创建了一个不小心返回VARCHAR
的SQL Scalar Function
......然后。。。使用它在VIEW
中生成列。VIEW
在DbContext
中正确映射...所以林克说它很好。 但是,实体预期日期时间?,VIEW
返回字符串。
哪个奇怪地扔...
"已经有一个与此命令关联的打开的 DataReader 必须先关闭"
很难弄清楚...但是在我更正了返回参数之后...一切都很好
除了Ladislav Mrnka的回答:
如果要在"设置"选项卡上发布和重写容器,则可以将"多个活动结果集"设置为 True。您可以通过单击"高级..."找到此选项,它将位于"高级"组下。
我通过更改解决了这个问题await _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();
解决了这个问题。
很可能是由于实体框架的"延迟加载"功能而发生的。通常,除非在初始读取期间明确要求,否则仅在需要时提取所有联接数据(存储在其他数据库表中的任何数据)。在许多情况下,这是一件好事,因为它可以防止获取不必要的数据,从而提高查询性能(无联接)并节省带宽。
在问题中所述的情况下,将执行初始提取,在"选择"阶段请求缺少延迟加载数据,发出其他查询,然后 EF 抱怨"打开 DataReader"。
接受的答案中提出的解决方法将允许执行这些查询,并且实际上整个请求将成功。
但是,如果您将检查发送到数据库的请求,您会注意到多个请求 - 每个丢失(延迟加载)数据的额外请求。这可能是性能杀手。
更好的方法是告诉 EF 在初始查询期间预加载所有需要的延迟加载数据。这可以使用"包含"语句来完成:
using System.Data.Entity;
query = query.Include(a => a.LazyLoadedProperty);
这样,将执行所有需要的连接,并且所有需要的数据将作为单个查询返回。问题中描述的问题将得到解决。
当我循环和更新数据时,同样的错误发生在我身上 IEnumerable<MyClass>
当我将循环集合更改为List<MyClass>
,并通过.ToList()
转换来填充它时,它解决并更新了,没有任何错误。
当我尝试在读取循环中更新某些记录时,我遇到了同样的错误。我已经尝试了MultipleActiveResultSets=true
投票最多的答案,发现这只是获取下一个错误的解决方法
适用于不允许新事务,因为有其他线程正在运行 在会话中
大型结果集的最佳方法是使用块并为每个块打开单独的上下文,如中所述来自实体框架的 SqlException - 不允许新事务,因为会话中还有其他线程在运行
对我来说,这是我自己的错误。 当我应该使用SqlCommand.ExecuteNonQuery()
时,我试图使用SqlCommand.executeReader()
运行INSERT
。 它已打开但从未关闭,从而导致错误。 注意这种疏忽。
从现实世界的场景中提取的:
- 代码在具有多个活动结果集
- 的阶段环境中运行良好 在连接字符串中设置了多个活动结果集 发布
- 到生产环境而不发布 MultipleActiveResultsSets=true 的代码
- 如此多的页面/调用工作,而一个页面/调用失败
- 仔细观察调用,对数据库进行了不必要的调用,需要删除
- 在生产中设置多个活动结果集=true并发布清理的代码,一切运行良好,高效
总之,在不忘记 MultipleActiveResultSet 的情况下,代码可能已经运行了很长时间,然后才发现可能非常昂贵的冗余数据库调用,我建议不要完全依赖于设置 MultipleActiveResultSets 属性,但也要找出代码失败时需要它的原因。
我在我的工具中使用 Web 服务,这些服务获取存储过程。 虽然更多的客户端工具获取 Web 服务,但会出现此问题。我已经通过为那些获取存储过程的函数指定 Synchronized 属性来修复。现在它工作正常,错误从未出现在我的工具中。
[MethodImpl(MethodImplOptions.Synchronized)]
public static List<t> MyDBFunction(string parameter1)
{
}
此属性允许一次处理一个请求。 所以这解决了问题。
就我而言,我必须将MultipleActiveResultSets
设置为在连接字符串中True
。
然后出现了另一个错误(真正的错误),关于无法在同一数据上下文上同时运行 2 个 (SQL) 命令!(EF 核心,代码优先)
因此,我的解决方案是查找任何其他异步命令执行并将它们转换为同步命令,因为我对这两个命令只有一个 DbContext。
希望对您有所帮助
使用启用了TransactionScopeAsyncFlowOption
的作用域Transaction
但忘记await
某些存储库方法,也会发生这种情况。
我正在迭代,已经通过查询。我通过放置一个.ToList() 在我的@foreach声明中。
foreach (var user in report.myUsers.ToList())
{
}