出于好奇和对更多洞察力的永恒渴望:)
这里有这个 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/