如果值为空,如何将值返回给 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<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);
【讨论】:
以上是关于如果值为空,如何将值返回给 sqldatareader?的主要内容,如果未能解决你的问题,请参考以下文章