出于好奇和对更多洞察力的永恒渴望:)

这里有这个 CLR 存储过程,它通过以下代码将结果发送回客户端。 SqlMetaData 数组附加到 SqlDataRecord。每个 SqlDataRecord 获取通过管道发送给客户端的值。

SqlMetaData[] columns = new SqlMetaData[1];

columns[0] = new SqlMetaData("bool", SqlDbType.Bit);

SqlDataRecord record = new SqlDataRecord(columns);
SqlContext.Pipe.SendResultsStart(record);

foreach (bool b in bools)
{
     record.SetBoolean(0, b);

      SqlContext.Pipe.SendResultsRow(record);
}
SqlContext.Pipe.SendResultsEnd();

客户端代码:
SqlCommand cmd = new SqlCommand("CLR_SPROC", connection)

SqlDataReader reader = cmd.ExecuteReader();

int b = reader.GetOrdinal("bool"); // b == 0 because it was added in index 0 in the SqlMetaData array

因此,“bool”的序数在第一个索引中首先找到时变为零。有趣的。

现在的问题是:

对于每个查询,SqlServer 是否都像这样在后台工作?我的意思是当执行查询时,查询解析器是否在最终选择中提取列名,从中构建一个 SqlMetaData 数组,将其附加到 SqlDataRecord 并通过流发送回?

所以查询“SELECT a,b,c FROM table”

变成
SqlMetaData[] columns = new SqlMetaData[3];

columns[0] = new SqlMetaData("a", SqlDbType.Int);
columns[1] = new SqlMetaData("b", SqlDbType.Int);
columns[2] = new SqlMetaData("c", SqlDbType.Int);

 SqlDataRecord record = new SqlDataRecord(columns);
 SqlContext.Pipe.SendResultsStart(record);

foreach(...)
{
  record.SetInt32(0, a);
  record.SetInt32(1, b);
  record.SetInt32(2, c);
  SqlContext.Pipe.SendResultsRow(record);
}

最佳答案

SQL Server 使用 TDS 协议(protocol)(表格数据流)与客户端通信。 TDS 是一种流协议(protocol),它包括描述结果集的元数据,后跟结果集数据流。结果集中的记录包含相同的列数、列名和数据类型,因此处理结果集所需的元数据只需要发送一次,而不是附加到每条记录。

SqlClient 等客户端 API 将低级 TDS 结构公开为高级对象,如 SqlMetaData、SqlDataRecord 和 SqlDataReader。尽管您针对客户端 API 而不是直接针对 TDS 进行编码,但您可能会发现对 TDS 通信的粗略理解很有趣,因为它提供了 SQL Server 如何在幕后工作的 View 。您可以在 http://msdn.microsoft.com/en-us/library/dd304523.aspx 找到 TDS 协议(protocol)的详细信息。

关于c# - SqlDataReader 和元数据的内部工作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24426666/

10-11 01:35
查看更多