当SqlReader正在读取时,存储过程结果集存储在哪里?



As per docsSqlCommandTimeoutis

该属性是所有网络数据包的累积超时在方法调用期间读取的所有网络读取在命令执行或处理结果期间。暂停罐仍然在第一行返回后发生,并且不包括user处理时间,只有网络读取时间。

例如,在30秒超时情况下,如果Read需要两个网络数据包,然后它有30秒的时间来读取两个网络数据包。如果你再次调用Read,它将有另外30秒的时间读取任何数据它需要.

下面的代码执行存储过程,然后使用SqlReader逐行读取数据。

public static async Task<IEnumerable<AvailableWorkDTO>> prcGetAvailableWork(this MyDBContext dbContext, int userID)
{            
var timeout = 120
var result = new List<AvailableWorkDTO>();
using (var cmd = dbContext.Database.GetDbConnection().CreateCommand())
{
var p1 = new SqlParameter("@UserID", SqlDbType.Int)
{
Value = userID
};
cmd.CommandText = "dbo.prcGetAvailableWork";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(p1);
cmd.CommandTimeout = timeout;
await dbContext.Database.OpenConnectionAsync().ConfigureAwait(false);
using (var reader = await cmd.ExecuteReaderAsync().ConfigureAwait(false))
{
while (await reader.ReadAsync().ConfigureAwait(false))
{
var item = new AvailableWorkDTO();
item.ID = reader.GetInt32(0);
item.Name = reader.GetString(1);
item.Title = reader.GetString(2);
item.Count = reader.GetInt32(3);
result.Add(item);
}
}
}
return result;
}

在Sql Profiler中,我只看到一个对存储过程的调用。所以我猜存储过程执行并返回整个结果集。


1>如果SqlReader一次读取一条记录,那么当reader读取时,整个结果集存储在哪里?它是临时存储在SQL Server内存或应用服务器内存?

2>使用EF Core是否有办法一次读取整个结果集?

结果集不存储在任何地方,它直接流式传输到客户端。当服务器从磁盘或内存中读取行时,它们通过查询计划被馈送并通过网络输出。这就是为什么你总是需要确保尽可能快地读取,并释放读取器和连接:因为查询一直在运行。

要"立即读取整个结果集",只需执行现在正在执行的操作:循环读取器并将其添加到List中。或者,您可以使用DataTable.Load,但我不建议这样做,而且它也不是async

阅读器只是一个能够从命令返回单个行的对象。您在分析器中看到的是命令的一次执行。如果您还监视SQL:Batch Completed事件,您将看到只有在读取器完成时才会发生。

您可以使用EF而不是ADO的存储过程。

创建一个特殊的类来从存储过程中获取数据,或者使用现有的AvailableWorkDTO。该类应具有存储过程的select子句所具有的所有属性。您不需要选择存储过程中的所有内容。只需选择AvailableWorkDTO具有的属性并添加NotMapped属性
[NotMapped]
public class AvailableWorkDTO 
{
.....
}

在此之后将这个类添加到dbContext DbSet

public virtual DbSet<AvailableWorkDTO> AvailableWorkDTOs { get; set; }
下面是一个示例函数,演示如何使用存储过程 获取数据
public async Task<IEnumerable<AvailableWorkDTO>> prcGetAvailableWork(MyDBContext dbContext, int userID)
{ 
var pId = new SqlParameter("@UserID", userID);
return await dbContext.Set<AvailableWorkDTO>()
.FromSqlRaw("Execute db.prcGetAvailableWork @UserID", pId)
.ToArrayAsync();
}

最新更新