我正在使用 SQLdatareader 从数据库中构建 POCOs。代码运行良好,除非在数据库中遇到空值。例如,如果数据库中的 FirstName 列包含空值,将抛出异常。
employee.FirstName = sqlreader.GetString(indexFirstName);
如何在这种情况下处理空值?
我正在使用 SQLdatareader 从数据库中构建 POCOs。代码运行良好,除非在数据库中遇到空值。例如,如果数据库中的 FirstName 列包含空值,将抛出异常。
employee.FirstName = sqlreader.GetString(indexFirstName);
你需要检查 IsDBNull
:
if(!SqlReader.IsDBNull(indexFirstName))
{
employee.FirstName = sqlreader.GetString(indexFirstName);
}
那是您唯一可靠的检测和处理此情况的方式。
我将这些内容封装成扩展方法,并倾向于在列确实为null
时返回默认值:
public static string SafeGetString(this SqlDataReader reader, int colIndex)
{
if(!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
return string.Empty;
}
现在你可以这样调用它:
employee.FirstName = SqlReader.SafeGetString(indexFirstName);
从此你将不再担心异常或null
值。
int colIndex = reader.GetOrdinal(fieldname);
,然后轻松重载@marc_s的SafeGetString
函数。 - ilans您应该使用as
运算符与??
运算符来设置默认值。 值类型需要被标记为可为空,并赋予默认值。
employee.FirstName = sqlreader[indexFirstName] as string;
employee.Age = sqlreader[indexAge] as int? ?? default(int);
< p > as
运算符用于类型转换,包括检查DBNull。 sqlreader[indexAge] as string ?? ""
,则始终会得到 ""
。请考虑是否真正需要 (int?)sqlreader[indexAge] ?? defaultValue
,这样如果您的 SQL 发生更改,就会产生异常而不是错误值。@Stevo3000:default(int) 是 0,不是 -1。
@Chris:确保您正在使用您真正想要的那个。 - me22default(int)
,这里没有人建议default(int)
是-1。其次,你举的不使用as
的例子最多只能算幼稚,当然你可能会写错任何一行代码,这是任何代码的危险之一。使用as
的情况是它允许程序员编写针对可能包含DBNull(来自允许它或更有用的连接的表)的数据的代码。 - stevehipwellemployee.FirstName = sqlreader[indexFirstName] as string;
对于整数,如果你将其强制转换为可空整数类型,你可以使用GetValueOrDefault()方法。
employee.Age = (sqlreader[indexAge] as int?).GetValueOrDefault();
或者使用空值合并运算符 (??
)。
employee.Age = (sqlreader[indexAge] as int?) ?? 0;
IsDbNull(int)
通常比使用GetSqlDateTime
等方法然后与DBNull.Value
进行比较要慢得多。尝试使用这些扩展方法来操作SqlDataReader
。
public static T Def<T>(this SqlDataReader r, int ord)
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return default(T);
return ((INullable)t).IsNull ? default(T) : (T)t;
}
public static T? Val<T>(this SqlDataReader r, int ord) where T:struct
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return null;
return ((INullable)t).IsNull ? (T?)null : (T)t;
}
public static T Ref<T>(this SqlDataReader r, int ord) where T : class
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return null;
return ((INullable)t).IsNull ? null : (T)t;
}
这样使用它们:
var dd = r.Val<DateTime>(ords[4]);
var ii = r.Def<int>(ords[0]);
int nn = r.Def<int>(ords[0]);
if(reader.IsDBNull(ColumnIndex)) {// logic}
就像许多答案所说的那样有效。
我想提一下,如果你正在使用列名,只比较类型可能更容易。
if(reader["TeacherImage"].GetType() == typeof(DBNull)) { //logic }
我认为在使用列名从数据读取器返回行时,不存在NULL列值。
如果您使用datareader["columnName"].ToString();
,它将总是给您一个可以为空的值(如果需要比较,则为String.Empty
)。
我会使用以下内容,不会太担心:
employee.FirstName = sqlreader["columnNameForFirstName"].ToString();
你可以编写一个通用函数来检查 Null 值,并在其为 NULL 时包含默认值。在读取 Datareader 时调用此函数。
public T CheckNull<T>(object obj)
{
return (obj == DBNull.Value ? default(T) : (T)obj);
}
在读取Datareader时,请使用
while (dr.Read())
{
tblBPN_InTrRecon Bpn = new tblBPN_InTrRecon();
Bpn.BPN_Date = CheckNull<DateTime?>(dr["BPN_Date"]);
Bpn.Cust_Backorder_Qty = CheckNull<int?>(dr["Cust_Backorder_Qty"]);
Bpn.Cust_Min = CheckNull<int?>(dr["Cust_Min"]);
}
一种方法是检查数据库中的空值:
employee.FirstName = (sqlreader.IsDBNull(indexFirstName)
? ""
: sqlreader.GetString(indexFirstName));
这个解决方案不太依赖供应商,可以与SQL、OleDB和MySQL Reader一起使用:
public static string GetStringSafe(this IDataReader reader, int colIndex)
{
return GetStringSafe(reader, colIndex, string.Empty);
}
public static string GetStringSafe(this IDataReader reader, int colIndex, string defaultValue)
{
if (!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
else
return defaultValue;
}
public static string GetStringSafe(this IDataReader reader, string indexName)
{
return GetStringSafe(reader, reader.GetOrdinal(indexName));
}
public static string GetStringSafe(this IDataReader reader, string indexName, string defaultValue)
{
return GetStringSafe(reader, reader.GetOrdinal(indexName), defaultValue);
}
受到getpsyched的答案的启发,我创建了一个通用的方法,通过列名检查列值。
public static T SafeGet<T>(this System.Data.SqlClient.SqlDataReader reader, string nameOfColumn)
{
var indexOfColumn = reader.GetOrdinal(nameOfColumn);
return reader.IsDBNull(indexOfColumn) ? default(T) : reader.GetFieldValue<T>(indexOfColumn);
}
使用方法:
var myVariable = SafeGet<string>(reader, "NameOfColumn")