4

Я пытаюсь отлаживать ответ SQL, который бросает ошибку:Написать SqlDataReader для немедленного окна C#

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

Это не делает много смысла, как объект не имеет какой-либо Bools.

Код:

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.

EDIT

согласно запросу в комментарии

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 при отладке «на лету» в ближайшее окно?

+0

Вы используете некоторые расширения? Где происходит метод «Запрос »? – user3185569

+0

@ user3185569 Привет, я использую dapper, но он использует базовый механизм Sql-сервера. –

+0

Можете ли вы показать класс 'Rate' вместе с оператором' CREATE' вашей таблицы в SQL. Кажется, что несоответствие типов данных. – user3185569

ответ

2

Как написать 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 распечатанные в окне Immediate в виде строки 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(); 
     } 
    } 
} 

(Примечание - код, чтобы получить имя таблицы не полностью протестировано.)

Примечание Я использую сериализовать значение результатов и форматировать общие результаты. Если хотите, вы можете использовать другой сериализатор.

Создайте проект в режиме отладки и скопируйте его в удобное место, скажем 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 для ручной проверки.

0
  • Вы можете установить контрольную точку внутри кода Dapper - это Open Source.
  • Результат 1 определяется как varchar (50), но ваш класс C# говорит десятичный.
+0

Хорошее место, это означает, что где-то должен быть механизм преобразования, так как когда я изменил Result1 на строку в C#, он дал 100 с ошибками, еще лучше, когда я проверил, выберите «ВЫБРАТЬ отличную отливку» [[Result1] как десятичную (18,10))) FROM dbo. [Rates] 'он не дал мне никаких ошибок. На этом этапе я пойду поговорить с командой о том, кто написал это так (и почему), и что происходит с этим .... –

0

Conversion failed when converting the varchar value '0.01' to data type bit.
Я думаю, что сообщение выбрано SQL-сервером. поэтому на уровне SQL должна быть ошибка. Попробуйте проверить фактический запрос в профилировщике SQL и запустить в SSMS.

+0

Привет Par, он отлично работает при выполнении непосредственно. –

+0

Вы имеете в виду, если вы скопируете запрос на вставку из профилировщика в SSMS и запустите его? Я подозреваю, что проблема в запросе, потому что это сообщение приходит на уровне SQL (например: 'select convert (бит, '0.01')') – par