sql server语言 - 写入SqlDataReader到直接窗口c#



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

将varchar值"0.01"转换为数据类型位时,转换失败。

这没有多大意义,因为对象没有任何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 statobj, out bool dataReady) + 0x1ce1 bytes

此时我可以访问dataStream也就是SqlDataReader

我正在寻找一种方法来输出'原始'结果的SqlDataReader,像

System.Diagnostics.Debug.WriteLine((new System.IO.StreamReader(stream)).ReadToEnd());

but for 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实现接口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<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();
        }
    }
}

(注意-获取表名的代码没有完全测试。)

注意我使用json.net序列化结果值并格式化整体结果。如果您愿意,可以使用不同的序列化器。

在调试模式下构建项目,并将其复制到一个方便的位置,例如C:TempDataReaderDebugUtilities.dll

接下来,当需要将值转储到数据读取器中时,在直接窗口中键入:

Assembly.LoadFile(@"C:TempDataReaderDebugUtilities.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服务器抛出的。所以在SQL级别应该有错误。

相关内容

  • 没有找到相关文章

最新更新