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

employee.FirstName = sqlreader.GetString(indexFirstName);

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


当前回答

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

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

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

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

其他回答

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

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

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

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

一种方法是检查db是否为null:

employee.FirstName = (sqlreader.IsDBNull(indexFirstName) 
    ? ""
    : sqlreader.GetString(indexFirstName));

我们使用一系列静态方法从数据读取器中提取所有值。创建静态/共享方法的好处是,你不必一遍又一遍地做同样的检查…

静态方法将包含检查空值的代码(参见本页的其他答案)。