将SqlDataReader写入即时窗口c#
我正在尝试调试抛出错误的SQL响应:
将varchar值’0.01’转换为数据类型位时转换失败。
这没有多大意义,因为对象没有任何bool。
码:
using (var connection = _connectionProvider.GetDbConnection()) { connection.Open(); return connection.Query(query, parameters); }
执行的SQL(我手动添加参数):
select * from (select top 1 BuildNumber, RateVersion, SampleId, Tariff, TariffStepName, Factor1, Result1 from dbo.Rates where Tariff = 'Default' and TariffStepName = 'I_P' and (RateVersion <= 1) and Factor1 = 'false' and (SampleId is null) order by RateVersion desc, sampleId desc) top1
我将断点放在读取发生的位置( connection.Query(query, parameters)
),然后在exception时启用中断,当它失败时更深入地跳入堆栈到TdsParser TryRun()
(在抛出exception的情况下更高级别)
System.Data.dll!System.Data.SqlClient.TdsParser.TryRun(System.Data.SqlClient.RunBehavior runBehavior,System.Data.SqlClient.SqlCommand cmdHandler,System.Data.SqlClient.SqlDataReader dataStream,System.Data.SqlClient.BulkCopySimpleResultSet bulkCopyHandler,System.Data.SqlClient.TdsParserStateObject stateObj,out bool dataReady)+ 0x1ce1 bytes
此时我可以访问dataStream
,它是SqlDataReader
我正在寻找一种从SqlDataReader
输出’raw’结果的方法,比如说
System.Diagnostics.Debug.WriteLine((new System.IO.StreamReader(stream)).ReadToEnd());
但对于SqlDataReader
。
编辑
根据评论请求
public class Rate { public string Tariff { get; set; } public string TariffStepName { get; set; } public string Factor1 { get; set; } public string Factor2 { get; set; } public string Factor3 { get; set; } public string Factor4 { get; set; } public string Factor5 { get; set; } public string Factor6 { get; set; } public string Factor7 { get; set; } public string Factor8 { get; set; } public string Factor9 { get; set; } public string Factor10 { get; set; } public decimal Result1 { get; set; } public decimal Result2 { get; set; } public decimal Result3 { get; set; } public decimal Result4 { get; set; } public decimal Result5 { get; set; } public decimal Result6 { get; set; } public decimal Result7 { get; set; } public decimal Result8 { get; set; } public decimal Result9 { get; set; } public decimal Result10 { get; set; } public string TextResult1 { get; set; } public string TextResult2 { get; set; } public string TextResult3 { get; set; } public string TextResult4 { get; set; } public string TextResult5 { get; set; } public int? SampleId { get; set; } public int BuildNumber { get; set; } public decimal? RateVersion { get; set; } }
SQL
CREATE TABLE dbo.[Rates]( [BuildNumber] [int] NOT NULL, [Tariff] [varchar](30) NOT NULL, [TariffStepName] [varchar](60) NOT NULL, [Factor1] [varchar](50) NOT NULL, [Factor2] [varchar](50) NULL, [Factor3] [varchar](50) NULL, [Factor4] [varchar](50) NULL, [Factor5] [varchar](50) NULL, [Factor6] [varchar](50) NULL, [Factor7] [varchar](50) NULL, [Factor8] [varchar](50) NULL, [Factor9] [varchar](50) NULL, [Factor10] [varchar](50) NULL, [Result1] [varchar](50) NULL, [Result2] [decimal](19, 6) NULL, [Result3] [decimal](19, 6) NULL, [Result4] [decimal](19, 6) NULL, [Result5] [decimal](19, 6) NULL, [Result6] [decimal](19, 6) NULL, [Result7] [decimal](19, 6) NULL, [Result8] [decimal](19, 6) NULL, [Result9] [decimal](19, 6) NULL, [Result10] [decimal](19, 6) NULL, [RateVersion] [decimal](18, 2) NULL, [SampleId] [int] NULL, [TextResult1] [varchar](50) NULL, [TextResult2] [varchar](50) NULL, [TextResult3] [varchar](50) NULL, [TextResult4] [varchar](50) NULL, [TextResult5] [varchar](50) NULL )
编辑2:对于那些想知道是什么原因的人
声明实际上是通过其他机制转换为此声明
exec sp_executesql N'select * from (select top 1 BuildNumber, RateVersion, SampleId, Tariff, TariffStepName, Factor1, Result1 from dbo.Rates where Tariff = @Tariff and TariffStepName = @TariffStepName and (RateVersion <= @RV) and Factor1 = @Factor1 and (SampleId is null) order by RateVersion desc, sampleId desc) top1 ',N'@Tariff varchar(50),@TariffStepName varchar(50),@RV decimal(3,2),@Factor1 bit',@Tariff='Default',@TariffStepName='I_P',@RV=1.00,@Factor1=0 go
然后,当没有行时通过选择不是top 1
就像它的意图那样会失败并且会出现错误然后在那之后排不会
问题仍然存在: 如何在即时窗口调试时编写SqlDataReader?
在即时调试时如何编写SqlDataReader?
SqlDataReader
实现了接口IDataReader
。 以下技巧适用于实现此接口的任何读者。 与(new System.IO.StreamReader(stream)).ReadToEnd()
,这些技术将消耗数据读取器的内容,因此它将不再可用。
纯粹在飞行中倾倒结果。
如果您没有时间准备并需要立即查看读者的内容,可以将数据读取器加载到即时窗口中定义的DataTable
中,然后打印出该表的XML。
首先,通过键入以下内容在即时窗口中定义三个运行时全局变量:
object [] _objs = null; DataTable _table = null; DataSet _set = null;
每个会话执行一次。
接下来,如果代码已经开始读取表列,则可以通过键入以下内容来获取当前行的值:
_objs = new object[dataStream.FieldCount]; dataStream.GetValues(_objs); _objs
现在将显示当前值。
然后,要读入并显示其余行,请执行以下操作:
_table = new DataTable(); _table.Load(dataStream); _set = new DataSet(); _set.Tables.Add(_table); _set.GetXml(); Debug.WriteLine(_set.GetXml());
您将在立即窗口中看到_set
的内容作为XML字符串打印出来。 请注意,如果部分读取表, DataTable.Load(IDataReader)
将跳过当前行,因此首先转储当前值。
这适用于对应于单个表的读者,但不适用于与形成集合的多个表相对应的读者。
使用小型调试库转储结果。
如果您有一点时间准备或需要调试多表读取器,则可以执行以下操作。
首先,使用以下实用程序创建一个小型调试DLL项目。 您无需将其链接到实际调试的项目中。
namespace DataReaderDebugUtilities { public static class DataReaderExtensions { public static object[] CurrentValues(this IDataReader reader) { if (reader == null) throw new ArgumentNullException(); var objs = new object[reader.FieldCount]; reader.GetValues(objs); return objs; } public static KeyValuePair [] CurrentNamesAndValues(this IDataReader reader) { if (reader == null) throw new ArgumentNullException(); var query = Enumerable.Range(0, reader.FieldCount).Select(i => new KeyValuePair(reader.GetName(i), reader.GetValue(i))); return query.ToArray(); } public static string ToStringAsDataTable(this IDataReader reader) { if (reader == null) throw new ArgumentNullException(); var sb = new StringBuilder(); using (var textWriter = new StringWriter(sb)) using (var jsonWriter = new JsonTextWriter(textWriter) { Formatting = Formatting.Indented }) { var serializer = JsonSerializer.CreateDefault(); jsonWriter.WriteDataTable(reader, serializer); } return sb.ToString(); } public static string ToStringAsDataSet(this IDataReader reader) { if (reader == null) throw new ArgumentNullException(); var sb = new StringBuilder(); using (var textWriter = new StringWriter(sb)) using (var jsonWriter = new JsonTextWriter(textWriter) { Formatting = Formatting.Indented }) { var serializer = JsonSerializer.CreateDefault(); jsonWriter.WriteDataSet(reader, serializer); } return sb.ToString(); } } public static class JsonExtensions { public static void WriteDataTable(this JsonWriter writer, IDataReader reader, JsonSerializer serializer) { if (writer == null || reader == null || serializer == null) throw new ArgumentNullException(); writer.WriteStartArray(); while (reader.Read()) { writer.WriteStartObject(); for (int i = 0; i < reader.FieldCount; i++) { writer.WritePropertyName(reader.GetName(i)); serializer.Serialize(writer, reader[i]); } writer.WriteEndObject(); } writer.WriteEndArray(); } public static void WriteDataSet(this JsonWriter writer, IDataReader reader, JsonSerializer serializer) { if (writer == null || reader == null || serializer == null) throw new ArgumentNullException(); writer.WriteStartObject(); do { var tableName = string.Empty; var schemaTable = reader.GetSchemaTable(); if (schemaTable != null) tableName = schemaTable.Rows.Cast() .Select(r => r[schemaTable.Columns[System.Data.Common.SchemaTableColumn.BaseTableName]].ToString()) .FirstOrDefault(); writer.WritePropertyName(tableName ?? string.Empty); writer.WriteDataTable(reader, serializer); } while (reader.NextResult()); writer.WriteEndObject(); } } }
(注意 – 获取表名的代码未经过全面测试。)
注意我使用json.net来序列化结果值并格式化整体结果。 如果您愿意,可以使用不同的序列化程序。
以调试模式构建项目并将其复制到方便的位置,例如C:\Temp\DataReaderDebugUtilities.dll
。
接下来,当您需要在数据读取器中转储值时,在即时窗口中键入:
Assembly.LoadFile(@"C:\Temp\DataReaderDebugUtilities.dll");
现在,您可以在即时窗口中调用此DLL中的方法,即使它未链接到您的项目中。 因此打字:
DataReaderDebugUtilities.DataReaderExtensions.CurrentNamesAndValues(dataStream)
将显示当前行的名称和值(如果有)。
然后打字
string _s = DataReaderDebugUtilities.DataReaderExtensions.ToStringAsDataSet(dataStream);
要么
string _s = DataReaderDebugUtilities.DataReaderExtensions.ToStringAsDataTable(dataStream);
将读取器的剩余内容作为数据表或数据集转储到JSON字符串中以进行手动检查。
- 您可以在Dapper代码中设置断点 – 是开源。
- Result1定义为varchar(50),但您的C#类表示十进制。
Conversion failed when converting the varchar value '0.01' to data type bit.
我认为SQL Server会抛出该消息。 所以在SQL级别应该有错误。 尝试检查SQL事件探查器中的实际查询并在SSMS中运行。