c# - 将SqlDataReader写入立即窗口c#

标签 c# sql-server visual-studio-2013 immediate-window output-window

我正在尝试调试抛出错误的 SQL 响应:

Conversion failed when converting the varchar value '0.01' to data type bit.

这没有多大意义,因为对象没有任何 bool 值。

代码:

 using (var connection = _connectionProvider.GetDbConnection())
 {
    connection.Open();
    return connection.Query<Rate>(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<Rate>(query, parameters)),然后在异常时启用中断,当它失败时跳到更深的堆栈到 TdsParser TryRun() (抛出异常的级别更高)

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 中输出“原始”结果, 像

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
)

EDIT2:对于那些想知道原因是什么的人

语句实际上是通过额外的机制转换成这个的

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 实现接口(interface) IDataReader .以下技巧适用于任何实现此接口(interface)的阅读器。与 (new System.IO.StreamReader(stream)).ReadToEnd() 一样,这些技术将消耗数据读取器的内容,因此它不再可用。

纯粹即时转储结果。

如果您没有时间准备并且需要立即查看阅读器的内容,您可以将数据阅读器加载到即时窗口中定义的 DataTable 中,它们会打印出 XML对于那张 table 。

首先,在即时窗口中键入以下命令定义三个运行时全局变量:

object [] _objs = null;
DataTable _table = null;
DataSet _set = null;

每个 session 执行一次。

接下来,如果代码已经开始读取表格列,您可以通过键入以下内容获取当前行的值:

_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<string, object> [] CurrentNamesAndValues(this IDataReader reader)
        {
            if (reader == null)
                throw new ArgumentNullException();
            var query = Enumerable.Range(0, reader.FieldCount).Select(i => new KeyValuePair<string, object>(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<DataRow>()
                        .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();
        }
    }
}

(注意 - 获取表名的代码未经过全面测试。)

请注意,我使用的是 序列化结果值并格式化整体结果。如果愿意,您可以使用不同的序列化程序。

在 Debug模式下构建项目并将其复制到方便的位置,比如 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字符串供人工检查。

关于c# - 将SqlDataReader写入立即窗口c#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38953677/

相关文章:

sql-server - 无法在 Visual Studio 2010 中创建表,出现 'The specified module could not be found (exception from Hresult: 0x800700E)' 错误

c# - 系统.Data.SqlClient.SqlException (0x80131904) : Incorrect syntax near '.'

c# - 如何复制一个对象,然后将其与原始对象进行比较,看是否发生了变化?

sql-server - SQL 级联删除多列

c++ - Visual Studio 2013 代码分析卡在 native 代码上

c# - 无法创建新的 "Diagnostics with code fix"项目! (罗斯林+VS2013)

.net - 如何为我的 .NET MVC 项目(在 Azure 存储模拟器上)创建新的 CloudBlobContainer 实例?

c# - Entity Framework 以一对多方式替换集合的正确方法

c# - 正则表达式 - 替换除文件扩展名之外的所有点,特殊字符

sql-server - 如何在 SQL Server 中保存查询以使其在对象资源管理器中可见