我使用SQLdatareader从数据库构建poco。除非在数据库中遇到空值,否则代码可以正常工作。例如,如果数据库中的FirstName列包含空值,则抛出异常。

employee.FirstName = sqlreader.GetString(indexFirstName);

在这种情况下处理空值的最佳方法是什么?


当前回答

这些都不是我想要的:

 public static T GetFieldValueOrDefault<T>(this SqlDataReader reader, string name)
 {
     int index = reader.GetOrdinal(name);
     T value = reader.IsDBNull(index) ? default(T) : reader.GetFieldValue<T>(index);
     return value;
 }

其他回答

private static void Render(IList<ListData> list, IDataReader reader)
        {
            while (reader.Read())
            {

                listData.DownUrl = (reader.GetSchemaTable().Columns["DownUrl"] != null) ? Convert.ToString(reader["DownUrl"]) : null;
                //没有这一列时,让其等于null
                list.Add(listData);
            }
            reader.Close();
        }

if(reader.IsDBNull(ColumnIndex)) {// logic}就像许多答案所说的那样。

我想提一下,如果你使用列名,比较类型可能会更舒服。

if(reader["TeacherImage"].GetType() == typeof(DBNull)) { //logic }

这个方法依赖于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"];
}

你需要检查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);

而且您再也不用担心异常或空值了。

这里有很多有用的信息(和一些错误的信息)的答案,我想把它们放在一起。

这个问题的简短回答是检查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()。