我目前正在使用sql数据阅读器(在vb.net中)通过SQL Server 2008数据库中的存储过程提取文章对象。该对象的一部分包括以下两个属性:
theArticle.Truthfulness = ((myReader.GetInt32(myReader.GetOrdinal("Truthfulness"))))
theArticle.Relevance = ((myReader.GetInt32(myReader.GetOrdinal("Relevance"))))
我的问题是,真实性和相关性可能会返回一个空值,这会导致函数失效。
我想我理解为什么。我要求一个整数值(getin32),因为返回null失败。
如何容纳数据库中的空值,以免它倒下?
答案 0 :(得分:18)
您可以使用.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);
马克
答案 1 :(得分:2)
你检查过SqlDataReader.IsDBNull方法吗?可能类似于:
if(myReader.IsDBNull(myReader.GetOrdinal("Truthfulness"))
theArticle.Truthfulness = string.Empty;
else
theArticle.Truthfulness = ((myReader.GetInt32(myReader.GetOrdinal("Truthfulness"))))
答案 2 :(得分:1)
你知道,我一直在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;
}
}
为要返回的每种类型创建单独的重载。我主要使用string,int,date和decimal。记住YAGNI(您不需要使用阅读器支持的每种类型,只需使用您实际使用的类型。)
SQL Server这样的扩展类非常容易编写,并且可以大大简化您的工作。 相信我。我会欺骗你吗? :)
答案 3 :(得分:1)
这个通用版本可能有用:
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而不是强制转换?
答案 4 :(得分:0)
这是我们在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
答案 5 :(得分:0)
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&lt;&gt;不相容。
我怀疑人们需要完整的Sql类型作为C#模板,或者将ICOnvertible添加到它们中,以便能够只有一个或两个模板化方法。
如果有人可能有一个功能性技巧的想法或两个说出来:-)
答案 6 :(得分:-1)
现在,如果数据库返回它,您可能想要空值,因此您将使用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);
}
}