Answers:
您需要检查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
值了。
您应该将as
运算符与??
运算符结合使用以获得默认值。值类型将需要被读取为可空值并提供默认值。
employee.FirstName = sqlreader[indexFirstName] as string;
employee.Age = sqlreader[indexAge] as int? ?? default(int);
该as
运营商处理的铸造,包括支票的DBNull。
sqlreader[indexAge] as string ?? ""
,您将永远得到""
。考虑您是否真正想要(int?)sqlreader[indexAge] ?? defaultValue
替代,因此,如果您的SQL更改,您将获得异常而不是错误的值。@ Stevo3000:default(int)为0,而不是-1。@克里斯:确保您使用的是您真正想要的那个。
对于字符串,您可以简单地转换对象版本(使用数组运算符访问),并使用null字符串表示null:
employee.FirstName = (string)sqlreader[indexFirstName];
要么
employee.FirstName = sqlreader[indexFirstName] as string;
对于整数,如果将其强制转换为可为null的int,则可以使用GetValueOrDefault()
employee.Age = (sqlreader[indexAge] as int?).GetValueOrDefault();
或空值运算符(??
)。
employee.Age = (sqlreader[indexAge] as int?) ?? 0;
null
与之类似,它们不是DBNull对象。这两个语句之间的区别是,如果不是字符串,则第一个语句将失败,而如果不是字符串,则第二个语句将仅返回null。
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]);
我不认为使用列名在datareader中返回行时没有NULL列值。
如果这样做datareader["columnName"].ToString();
,它将始终为您提供一个可以为空字符串的值(String.Empty
如果需要比较)。
我将使用以下内容,不必太担心:
employee.FirstName = sqlreader["columnNameForFirstName"].ToString();
该解决方案与供应商的依赖性较小,可与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);
}
您可以编写一个泛型函数来检查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"]);
}
如何创建辅助方法
对于字符串
private static string MyStringConverter(object o)
{
if (o == DBNull.Value || o == null)
return "";
return o.ToString();
}
用法
MyStringConverter(read["indexStringValue"])
对于Int
private static int MyIntonverter(object o)
{
if (o == DBNull.Value || o == null)
return 0;
return Convert.ToInt32(o);
}
用法
MyIntonverter(read["indexIntValue"])
对于日期
private static DateTime? MyDateConverter(object o)
{
return (o == DBNull.Value || o == null) ? (DateTime?)null : Convert.ToDateTime(o);
}
用法
MyDateConverter(read["indexDateValue"])
注意:对于DateTime,将varialbe声明为
DateTime? variable;
除了marc_s的答案之外,您可以使用更通用的扩展方法从SqlDataReader获取值:
public static T SafeGet<T>(this SqlDataReader reader, int col)
{
return reader.IsDBNull(col) ? default(T) : reader.GetFieldValue<T>(col);
}
通过影响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")
您可以使用条件运算符:
employee.FirstName = sqlreader["indexFirstName"] != DBNull.Value ? sqlreader[indexFirstName].ToString() : "";
这里有很多有用的信息(和一些错误的信息)的答案,我想将它们结合在一起。
这个问题的简短答案是检查DBNull-几乎每个人都同意这一点:)
通用方法不必使用辅助方法来读取每种SQL数据类型的可为空的值,而是可以使用更少的代码来解决此问题。但是,您不能为可空值类型和引用类型都使用单个通用方法,这在Nullable类型中作为通用参数进行了详细讨论 吗?和C#通用类型约束,所有内容都可以为null。
因此,根据来自@ZXX和@getpsyched的答案,我们最终得到了两种用于获取可为空的值的方法,并且我为非空值添加了第三个方法(它基于方法命名来完成设置)。
public static T? GetNullableValueType<T>(this SqlDataReader sqlDataReader, string columnName) where T : struct
{
int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
return sqlDataReader.IsDBNull(columnOrdinal) ? (T?)null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
}
public static T GetNullableReferenceType<T>(this SqlDataReader sqlDataReader, string columnName) where T : class
{
int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
return sqlDataReader.IsDBNull(columnOrdinal) ? null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
}
public static T GetNonNullValue<T>(this SqlDataReader sqlDataReader, string columnName)
{
int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
return sqlDataReader.GetFieldValue<T>(columnOrdinal);
}
我通常使用列名,如果使用列索引,请更改它们。基于这些方法名称,我可以判断我是否期望数据为空,这在查看很久以前编写的代码时非常有用。
提示;
最后,在测试所有SQL Server数据类型的上述方法时,我发现您无法直接从SqlDataReader获取char [],如果想要char [],则必须获取字符串并使用ToCharArray()。
此方法取决于indexFirstName,该索引应该是从零开始的列序号。
if(!sqlReader.IsDBNull(indexFirstName))
{
employee.FirstName = sqlreader.GetString(indexFirstName);
}
如果您不知道列索引但不想检查名称,则可以使用以下扩展方法:
public static class DataRecordExtensions
{
public static bool HasColumn(this IDataRecord dr, string columnName)
{
for (int i=0; i < dr.FieldCount; i++)
{
if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
return true;
}
return false;
}
}
并使用如下方法:
if(sqlReader.HasColumn("FirstName"))
{
employee.FirstName = sqlreader["FirstName"];
}
旧问题,但也许有人仍然需要答案
实际上,我像这样解决了这个问题
对于int:
public static object GatDataInt(string Query, string Column)
{
SqlConnection DBConn = new SqlConnection(ConnectionString);
if (DBConn.State == ConnectionState.Closed)
DBConn.Open();
SqlCommand CMD = new SqlCommand(Query, DBConn);
SqlDataReader RDR = CMD.ExecuteReader();
if (RDR.Read())
{
var Result = RDR[Column];
RDR.Close();
DBConn.Close();
return Result;
}
return 0;
}
字符串相同,只是返回“”而不是0,因为“”为空字符串
所以你可以像
int TotalPoints = GatDataInt(QueryToGetTotalPoints, TotalPointColumn) as int?;
和
string Email = GatDatastring(QueryToGetEmail, EmailColumn) as string;
非常灵活,因此您可以插入任何查询以读取任何列,并且永远不会返回错误
以下是基于@marc_s答案的其他人可以使用的帮助程序类:
public static class SQLDataReaderExtensions
{
public static int SafeGetInt(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.IsDBNull(fieldIndex) ? 0 : dataReader.GetInt32(fieldIndex);
}
public static int? SafeGetNullableInt(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.GetValue(fieldIndex) as int?;
}
public static string SafeGetString(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.IsDBNull(fieldIndex) ? string.Empty : dataReader.GetString(fieldIndex);
}
public static DateTime? SafeGetNullableDateTime(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.GetValue(fieldIndex) as DateTime?;
}
public static bool SafeGetBoolean(this SqlDataReader dataReader, string fieldName)
{
return SafeGetBoolean(dataReader, fieldName, false);
}
public static bool SafeGetBoolean(this SqlDataReader dataReader, string fieldName, bool defaultValue)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.IsDBNull(fieldIndex) ? defaultValue : dataReader.GetBoolean(fieldIndex);
}
}
转换明智地处理DbNull。
employee.FirstName = Convert.ToString(sqlreader.GetValue(indexFirstName));
int colIndex = reader.GetOrdinal(fieldname);
并轻松重载@marc_s的SafeGetString
函数。