如果值为空,如何将值返回给 sqldatareader?

Posted

技术标签:

【中文标题】如果值为空,如何将值返回给 sqldatareader?【英文标题】:How do I return a value to a sqldatareader if value is null? 【发布时间】:2009-10-03 10:33:52 【问题描述】:

我目前正在使用 sql 数据阅读器(在 vb.net 中)通过存储过程从 SQL Server 2008 数据库中提取文章对象。该对象的一部分包括如下所示的两个属性:

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

我的问题是真实性和相关性可能会返回一个空值,这会导致函数崩溃。

我想我明白为什么了。我要求一个整数值(getin32),因为返回 null 它失败。

如何容纳数据库中的空值,使其不会倒下?

【问题讨论】:

【参考方案1】:

您可以使用.IsDBNull() 检查给定的序数位置是否为空,然后执行某些操作 - 例如将您的值设置为 -1 或其他值:

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

if(myReader.IsDBNull(myOrdinal))

  theArticle.Truthfulness = -1;

else

  theArticle.Truthfulness = myReader.GetInt32(myOrdinal);

正如 Mike Hofer 在他的回答中指出的那样,您也可以将所有这些逻辑包装到一个扩展方法中:

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);

马克

【讨论】:

或者捕获异常并处理 是的,你也可以这样做——但避免异常比捕获和处理异常要好(通常) @marc_s :同意您对我的回答的评论。删除它。谢谢你说清楚。您的评论是“我不认为这会起作用,因为如果 db 列为 NULL,则 .GetInt32() 调用将失败并出现异常 - 您将无法返回 NULL 值,然后您可以将其输入“ ??" 运算符...." 现在您可能会返回一个可为空的 int:***.com/a/53391141/572644【参考方案2】:

你检查了吗,SqlDataReader.IsDBNull 方法?大概是这样的:

if(myReader.IsDBNull(myReader.GetOrdinal("Truthfulness"))
theArticle.Truthfulness = string.Empty;
else
theArticle.Truthfulness = ((myReader.GetInt32(myReader.GetOrdinal("Truthfulness"))))

【讨论】:

好吧,如果你处理的是 int32 属性,string.Empty 不会有什么好处......【参考方案3】:

您知道,我一直在 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;
    

为要返回的每种类型创建一个单独的重载。我主要使用字符串、整数、日期和小数。请记住 YAGNI(您不需要使用阅读器支持的每种类型,只需使用您实际使用的类型即可。)

像这样的 SQL Server 扩展类非常容易编写,并且会极大地简化您的工作。 相信我。我会骗你吗? :)

【讨论】:

我认为这行不通,因为如果数据库中的列是 NULL,那么调用 GetInt32() 将导致异常。您无法将 GetInt32() 调用与 DBNull.Value 进行比较并对此做出反应.... 它起作用的原因是因为我们使用了短路 ?: 运算符。如果它不为空,我们将其返回。否则,我们返回默认值。 实际上,至少对于 SQL Server,它确实 NOT 工作 - 如果基础 db 列包含 NULL,GetInt32() 将抛出异常,并且您无法比较 GetInt32( ) 调用 DBNull.Value - VS2008 会抱怨甚至不编译它。 但我绝对喜欢将其包装在扩展方法中的想法 - 让生活更轻松! 我尝试使用您的方法并将 reader.GetInt32() 的输出与 SQL Server 中的 DBNull.Value 进行比较:我得到的只是此错误消息:运算符 '!=' 不能应用于操作数'int' 和 'System.DBNull' 类型的【参考方案4】:

这个通用版本可能有用:

    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 而不是强制转换?

【讨论】:

我喜欢这个选项,除了 IndexOutOfRangeException catch 语句。我认为您希望尽快知道架构结构是否已更改,而不是将默认值推送到系统的其他部分。【参考方案5】:

IsDbNull(int) 通常比使用 GetSqlInt32 之类的方法然后与 DBNull.Value 比较或使用它自己的 .IsNull Like 慢得多:

    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 以便能够只有一两个模板化方法。

如果有人有一个或两个功能技巧的想法,请说出来:-)

【讨论】:

【参考方案6】:

这是我们在 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

【讨论】:

【参考方案7】:

现在,如果数据库返回 null,您可能想要 null,因此您可以使用 Nullable&lt;int&gt;

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);
    

【讨论】:

以上是关于如果值为空,如何将值返回给 sqldatareader?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查 SQLDataReader 是不是没有行

将值传递给文本文件时停止附加

ASP .NET MVC Redirecttoaction 将参数传递给 Index 但值为空

HttpResponse返回的值为空

如何将值从python传递给c++并返回?

如果jsp表单元素的值为空,如何避免null出现在页面上?