已经有一个与此命令关联的打开DataReader,必须先关闭它
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了已经有一个与此命令关联的打开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
如果在迭代另一个查询的结果时执行查询,则会发生这种情况。从您的示例中发现这种情况并不清楚,因为示例未完成。
导致这种情况的一件事是在迭代某些查询的结果时触发了延迟加载。
通过在连接字符串中允许MARS可以轻松解决这个问题。将MultipleActiveResultSets=true
添加到连接字符串的提供程序部分(指定数据源,初始目录等)。
当我尝试更新读取循环中的某些记录时,我遇到了同样的错误。我已经尝试了最多投票的答案MultipleActiveResultSets=true
并发现,它只是解决方法来获取下一个错误
不允许新事务,因为会话中正在运行其他线程
适用于大型ResultSet的最佳方法是使用块并为每个块打开单独的上下文,如SqlException from Entity Framework - New transaction is not allowed because there are other threads running in the session中所述
我通过更改await _accountSessionDataModel.SaveChangesAsync()解决了这个问题; to _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操作尚未就绪。
对于那些通过谷歌找到这个; 我收到此错误是因为,正如错误所示,我在同一个SqlCommand上创建另一个之前未能关闭SqlDataReader,错误地认为在离开创建它的方法时它将被垃圾收集。
我在创建第二个阅读器之前调用sqlDataReader.Close();
解决了这个问题。
最有可能是因为Entity Framework的“延迟加载”功能而发生此问题。通常,除非在初始提取期间明确要求,否则仅在需要时提取所有连接的数据(存储在其他数据库表中的任何内容)。在许多情况下,这是一件好事,因为它可以防止获取不必要的数据,从而提高查询性能(无连接)并节省带宽。
在问题中描述的情况下,执行初始提取,并且在“选择”阶段期间,请求丢失延迟加载数据,发出附加查询,然后EF抱怨“打开DataReader”。
在接受的答案中提出的解决方法将允许执行这些查询,实际上整个请求将成功。
但是,如果您要检查发送到数据库的请求,您会注意到多个请求 - 对每个丢失(延迟加载)数据的额外请求。这可能是一个性能杀手。
更好的方法是告诉EF在初始查询期间预加载所有需要的延迟加载数据。这可以使用“Include”语句完成:
using System.Data.Entity;
query = query.Include(a => a.LazyLoadedProperty);
这样,将执行所有需要的连接,并且所有需要的数据将作为单个查询返回。问题中描述的问题将得到解决。
我在我的工具中使用Web服务,这些服务获取存储过程。当更多数量的客户端工具获取Web服务时,会出现此问题。我通过为这些函数指定Synchronized属性来修复存储过程。现在它工作正常,错误从未出现在我的工具中。
[MethodImpl(MethodImplOptions.Synchronized)]
public static List<t> MyDBFunction(string parameter1)
{
}
此属性允许一次处理一个请求。所以这解决了问题。
对我来说这是我自己的错误。当我应该使用INSERT
时,我试图使用SqlCommand.executeReader()
运行SqlCommand.ExecuteNonQuery()
。它被打开并且从未关闭,导致错误。注意这种疏忽。
这是从现实世界场景中提取的:
- 代码在Stage环境中运行良好,在连接字符串中设置了MultipleActiveResultSets
- 在没有MultipleActiveResultSets = true的情况下将代码发布到生产环境
- 如此多的页面/调用工作,而单个页面/调用失败
- 仔细观察呼叫,对数据库进行了不必要的调用,需要将其删除
- 在Production中设置MultipleActiveResultSets = true并发布已清理的代码,一切运行良好且高效
总而言之,在不忘记MultipleActiveResultSets的情况下,代码可能已经运行了很长时间才发现可能成本非常高的冗余db调用,我建议不要完全依赖于设置MultipleActiveResultSets属性,还要找出代码需要它的原因失败的地方。
作为旁注......当SQL Objects的(内部)数据映射出现问题时,也会发生这种情况。
例如...
我创建了一个SQL Scalar Function
,意外地返回了VARCHAR
......然后......用它在VIEW
中生成一个列。 VIEW
在DbContext
中正确映射...所以Linq称它为好。但是,实体期望DateTime?并且VIEW
正在返回String。
哪个奇怪的投掷......
“已经有一个与此命令关联的开放DataReader必须先关闭”
很难弄明白......但在我更正了返回参数之后......一切都很顺利
就我而言,我必须在连接字符串中将MultipleActiveResultSets
设置为True
。
然后它出现了另一个错误(真正的错误)关于无法在同一数据上下文中同时运行2(SQL)命令! (EF核心,代码优先)
因此,我的解决方案是查找任何其他异步命令执行并将它们转换为同步,因为我只有一个DbContext用于这两个命令。
我希望它对你有所帮助
您可以在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;
}
使用语法.ToList()
将从db读取的对象转换为list以避免再次重新读取。希望这对它有用。谢谢。
这是一个需要引用的人的工作连接字符串。
<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上下文从活动查询中调用DateLastUpdated,DateLastUpdate向数据存储本身发出命令。实体框架一次只支持每个上下文一个活动命令。
您可以将上述两个查询重构为如下所示:
return accounts.AsEnumerable()
.Select((account, index) => new AccountsReport()
{
RecordNumber = FormattedRowNumber(account, index + 1),
CreditRegistryId = account.CreditRegistryId,
DateLastUpdated = (
from h in context.AccountHistory
wher以上是关于已经有一个与此命令关联的打开DataReader,必须先关闭它的主要内容,如果未能解决你的问题,请参考以下文章
已经有一个打开的 DataReader 与此命令关联,必须先关闭
已经有一个与此命令关联的打开的 DataReader 必须首先关闭 linq [重复]
调用另一个 repo 时出错 - '已经有一个打开的 DataReader 与此命令关联,必须先关闭'
已经有一个打开的 DataReader 与此命令关联,必须先关闭