Как вернуть значение в sqldatareader, если значение равно нулю? - PullRequest
5 голосов
/ 03 октября 2009

В настоящее время я использую средство чтения данных sql (в vb.net) для извлечения объекта статьи через сохраненный процесс из базы данных SQL Server 2008. Часть этого объекта включает в себя два свойства, показанные ниже:

theArticle.Truthfulness = ((myReader.GetInt32(myReader.GetOrdinal("Truthfulness"))))
theArticle.Relevance = ((myReader.GetInt32(myReader.GetOrdinal("Relevance"))))

Моя проблема в том, что Истина и Релевантность могут возвращать нулевое значение, и это вызывает падение функции.

Кажется, я понимаю, почему. Я запрашиваю целочисленное значение (getin32) и, поскольку возвращается значение null, происходит сбой.

Как разместить нулевое значение в базе данных, чтобы оно не упало?

Ответы [ 7 ]

18 голосов
/ 03 октября 2009

Вы можете проверить, является ли данная порядковая позиция нулевой, используя .IsDBNull(), а затем сделать что-то - например, установите значение -1 или что-то в этом роде:

int myOrdinal = myReader.GetOrdinal("Truthfullness");

if(myReader.IsDBNull(myOrdinal))
{
  theArticle.Truthfulness = -1;
}
else
{
  theArticle.Truthfulness = myReader.GetInt32(myOrdinal);
}

Как отмечает Майк Хофер в своем ответе, вы также можете обернуть всю эту логику в метод расширения:

public static class SqlDataReaderExtensions 
{
    public static int SafeGetInt32(this SqlDataReader reader, 
                                   string columnName, int defaultValue) 
    {
        int ordinal = reader.GetOrdinal(columnName);

        if(!reader.IsDbNull(ordinal))
        {
           return reader.GetInt32(ordinal);
        } 
        else
        {
           return defaultValue;
        }
    }
}

, а затем просто используйте этот метод "SafeGetInt32" вместо:

  theArticle.Truthfulness = myReader.SafeGetInt32("Truthfullness", -1);

Марк

2 голосов
/ 03 октября 2009

Вы проверяли, метод SqlDataReader.IsDBNull? Возможно что-то вроде:

if(myReader.IsDBNull(myReader.GetOrdinal("Truthfulness"))
theArticle.Truthfulness = string.Empty;
else
theArticle.Truthfulness = ((myReader.GetInt32(myReader.GetOrdinal("Truthfulness"))))
1 голос
/ 07 ноября 2012

Эта общая версия может быть полезна:

    private T ValueOrDefault<T>(System.Data.IDataReader rdr, string columnName)
    {
        T vod = default(T);
        try
        {
            int idx = rdr.GetOrdinal(columnName);
            if (!rdr.IsDBNull(idx))
                return (T)rdr[idx];
        }
        catch (IndexOutOfRangeException) { }

        return vod;
    }

Может быть расширен для перехвата InvalidCastException или использовать Convert.ChangeType вместо приведения?

1 голос
/ 03 октября 2009

Знаете, я все время этим занимаюсь в Oracle. Чтобы очистить код, я написал набор методов расширения для упрощения операции:

using System.Data.OracleClient;
public static class OracleDataReaderExtensions 
{
    public static int GetInt32(this OracleDataReader reader, string columnName, int defaultValue) 
    {
        return reader.GetInt32(reader.GetOrdinal(columnName)) != DbNull.Value ? 
               reader.GetInt32(reader.GetOrdinal(columnName)) : 
               defaultValue;
    }
}

Создайте отдельную перегрузку для каждого типа, который вы хотите вернуть. Я в основном работаю со строкой, int, датой и десятичной дробью. Помните YAGNI (вам не нужно работать со всеми типами, поддерживаемыми ридером, только с теми, которые вы на самом деле используете.)

Такой класс расширения для SQL Server действительно прост в написании, и он значительно упростит вашу работу. Поверь мне в этом. Буду ли я лгать тебе? :)

0 голосов
/ 20 ноября 2018

В настоящее время вы, вероятно, хотите получить значение NULL, если база данных возвращает его, и поэтому вы должны использовать Nullable<int>:

public static class Extensions
{
    public static int? GetNullableInt32(this SqlDataReader reader, int ordinal)
    {
        if (reader.IsDBNull(ordinal))
            return null;

        return reader.GetInt32(ordinal);
    }

    public static long? GetNullableInt64(this SqlDataReader reader, int ordinal)
    {
        if (reader.IsDBNull(ordinal))
            return null;

        return reader.GetInt64(ordinal);
    }
}
0 голосов
/ 22 июля 2010

IsDbNull (int) обычно намного медленнее, чем использование методов, таких как GetSqlInt32, а затем сравнение с DBNull.Value или его собственным .IsNull Как:

    public static int Int32(this SqlDataReader r, int ord)
    {
        var t = r.GetSqlInt32(ord);
        return t.IsNull ? default(int) : t.Value;
    }

Пробовал несколько шаблонных решений, но пока безрезультатно. Проблема заключается в том, что все типы Sql (здесь SqlInt32) на самом деле являются структурами, и хотя все они имеют свойство .Value, C # не имеет реальных шаблонов для обработки этого. Также у них есть собственный интерфейс INullable, который имеет только .IsNull и не совместим с Nyllable <>.

Я подозреваю, что потребуется полный набор Sql-типов в качестве шаблонов C # или для добавления к ним ICOnvertible, чтобы иметь возможность иметь только один или два шаблонных метода.

Если у кого-то есть идея с функциональной уловкой или двумя, говорите :-)

0 голосов
/ 16 июля 2010

Вот что мы используем в SQLServer, и он работает как шарм:

...

  Dim X as Object = pbDr("TotAmt")  'dr is dim'ed as a DataReader

...

  Public Function pbDr(ByVal drName As String) As Object

    Dim SQLError As SqlClient.SqlException

    Dim IsNull As Boolean

    Dim Ordinal, DispNbr As Integer

    Try
      Ordinal = dr.GetOrdinal(drName)
      IsNull = dr.IsDBNull(Ordinal)
      If IsNull Then
        Dim Dbtype As String = dr.GetFieldType(Ordinal).ToString
        If Dbtype = "System.String" Then
          Return ""
        ElseIf Dbtype = "System.Int32" _
         OrElse Dbtype = "System.Double" _
         OrElse Dbtype = "System.Decimal" _
         OrElse Dbtype = "System.Int16" Then
          Return 0
        Else
          MsgBox("Print This Screen And Send To Support" _
           & "pbdr-Object = " & Dbtype, MsgBoxStyle.Critical)
          Return ""
        End If
      Else
        Return dr(Ordinal)
      End If

    Catch sqlerror
      Call DispSQLError(SQLError, "pbDr")
      pbDr = ""
    End Try

  End Function
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...