我使用SQLdatareader从数据库构建poco。除非在数据库中遇到空值,否则代码可以正常工作。例如,如果数据库中的FirstName列包含空值,则抛出异常。
employee.FirstName = sqlreader.GetString(indexFirstName);
在这种情况下处理空值的最佳方法是什么?
我使用SQLdatareader从数据库构建poco。除非在数据库中遇到空值,否则代码可以正常工作。例如,如果数据库中的FirstName列包含空值,则抛出异常。
employee.FirstName = sqlreader.GetString(indexFirstName);
在这种情况下处理空值的最佳方法是什么?
当前回答
当在数据读取器中使用列名返回行时,我不认为有NULL列值。
如果你做datareader["columnName"].ToString();它总是会给你一个值,可以是一个空字符串(字符串。如果需要比较,则为空)。
我会使用以下方法,不会太担心:
employee.FirstName = sqlreader["columnNameForFirstName"].ToString();
其他回答
你需要检查IsDBNull:
if(!SqlReader.IsDBNull(indexFirstName))
{
employee.FirstName = sqlreader.GetString(indexFirstName);
}
这是检测和处理这种情况的唯一可靠方法。
我把这些东西包装到扩展方法中,如果列确实为空,则倾向于返回默认值:
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);
而且您再也不用担心异常或空值了。
我尽了最大努力从DataTable中重新实现Field方法。https://learn.microsoft.com/en-us/dotnet/api/system.data.datarowextensions.field
如果您尝试转换DBNull,它将抛出。值转换为非空类型。否则它将转换为DBNull。值为null。
我还没有完全测试过。
public static T Field<T>(this SqlDataReader sqlDataReader, string columnName)
{
int columnIndex = sqlDataReader.GetOrdinal(columnName);
if (sqlDataReader.IsDBNull(columnIndex))
{
if (default(T) != null)
{
throw new InvalidCastException("Cannot convert DBNULL value to type " + typeof(T).Name);
}
else
{
return default(T);
}
}
else
{
return sqlDataReader.GetFieldValue<T>(columnIndex);
}
}
用法:
string fname = sqlDataReader.Field<string>("FirstName");
int? age = sqlDataReader.Field<int?>("Age");
int yearsOfExperience = sqlDataReader.Field<int?>("YearsEx") ?? 0;
if(reader.IsDBNull(ColumnIndex)) {// logic}就像许多答案所说的那样。
我想提一下,如果你使用列名,比较类型可能会更舒服。
if(reader["TeacherImage"].GetType() == typeof(DBNull)) { //logic }
这里有很多有用的信息(和一些错误的信息)的答案,我想把它们放在一起。
这个问题的简短回答是检查DBNull -几乎每个人都同意这一点:)
与使用辅助方法读取每个SQL数据类型的可空值不同,泛型方法允许我们用更少的代码来解决这个问题。然而,对于可空值类型和引用类型,你不能有一个单一的泛型方法,这将在中详细讨论 可空类型作为泛型参数可能吗?和c#泛型类型约束为所有可空的。
所以,从@ZXX和@getpsyched的答案中,我们最终得到了这个,2个方法用于获取可空值,我已经添加了第三个非空值(它完成了基于方法命名的集合)。
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);
}
我通常使用列名,如果你使用列索引,可以修改这些。根据这些方法名,我可以判断我是否期望数据为空,这在查看很久以前编写的代码时非常有用。
提示;
数据库中没有可空列可以避免这个问题。如果你 对数据库有控制那么列应该非空由 默认值,只在必要时为空。 不要强制转换数据库值 使用c#的“as”操作符,因为如果强制转换错误,它就会 静默返回null。 使用默认值表达式将会改变 数据库空值到非空值的值类型,如int, datetime, 钻头等。
最后,在测试所有SQL Server数据类型的上述方法时,我发现你不能直接从SqlDataReader中获得一个char[],如果你想要一个char[],你必须获得一个字符串并使用ToCharArray()。
Convert明智地处理DbNull。
employee.FirstName = Convert.ToString(sqlreader.GetValue(indexFirstName));