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

employee.FirstName = sqlreader.GetString(indexFirstName);

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


当前回答

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

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

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

其他回答

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

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

下面是其他人可以根据@marc_s的答案使用的helper类:

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);
        }
    }

在尝试读取它之前检查sqlreader.IsDBNull(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;

老问题了,但也许有人还需要一个答案

在现实生活中,我就是这样解决这个问题的

对于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?;

and

string Email = GatDatastring(QueryToGetEmail, EmailColumn) as string;

非常灵活,所以你可以插入任何查询读取任何列,它永远不会返回错误