将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中运行。