SQL数据读取器 – 处理空列值
我正在使用SQLdatareader从数据库中build立POCO。 代码工作,除非在数据库中遇到空值。 例如,如果数据库中的FirstName列包含空值,则会引发exception。
employee.FirstName = sqlreader.GetString(indexFirstName); 在这种情况下处理空值的最好方法是什么?
 你需要检查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); 
 而且您再也不必担心exception或null值。 
 你应该使用as运算符结合?? 运算符为默认值。 值types将需要读取为可空,并给予默认值。 
 employee.FirstName = sqlreader[indexFirstName] as string; employee.Age = sqlreader[indexAge] as int? ?? default(int); 
  as运算符处理包括DBNull检查的强制转换。 
对于一个string,你可以简单地强制转换对象版本(使用数组运算符访问),然后用空string作为空值:
 employee.FirstName = (string)sqlreader[indexFirstName]; 
要么
 employee.FirstName = sqlreader[indexFirstName] as string; 
对于整数,如果你转换为一个可空的int,你可以使用GetValueOrDefault()
 employee.Age = (sqlreader[indexAge] as int?).GetValueOrDefault(); 
 或空合并运算符( ?? )。 
 employee.Age = (sqlreader[indexAge] as int?) ?? 0; 
  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]); 
一种方法是检查数据库空值:
 employee.FirstName = (sqlreader.IsDBNull(indexFirstName) ? "" : sqlreader.GetString(indexFirstName)); 
当使用列名在数据读取器中返回行时,我不认为有一个NULL列值。
 如果你做datareader["columnName"].ToString(); 它总是会给你一个可以是空string的值(如果你需要比较,则为String.Empty )。 
我会使用以下,不会太担心:
 employee.FirstName = sqlreader["columnNameForFirstName"].ToString(); 
此解决scheme不依赖于供应商,可与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); } 
  reader.IsDbNull(ColumnIndex)尽可能多的答案说。 
我想提一下,如果你使用列名,只是比较types可能会更舒适。
 if(reader["TeacherImage"].GetType() == typeof(DBNull)) { //logic } 
我倾向于用合适的东西replaceSELECT语句中的空值。
 SELECT ISNULL(firstname, '') FROM people 
在这里,我用一个空白stringreplace每个null。 在这种情况下,你的代码不会出错。
 在尝试读取之前检查sqlreader.IsDBNull(indexFirstName) 。 
我想你会想要使用:
 SqlReader.IsDBNull(indexFirstName) 
您可以编写一个通用函数来检查Null,并在NULL时包含默认值。 在读取数据读取器时调用它
 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"]); } 
 我们使用一系列静态方法从数据读取器中提取所有值。 所以在这种情况下,我们将调用DBUtils.GetString(sqlreader(indexFirstName))创build静态/共享方法的好处是,你不必一遍又一遍地做同样的检查… 
静态方法将包含检查空值的代码(参见本页的其他答案)。
我正在使用下面列出的代码来处理读入数据表的Excel工作表中的空单元格。
 if (!reader.IsDBNull(2)) { row["Oracle"] = (string)reader[2]; } 
 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(); } 
和/或使用三元运算符赋值:
 employee.FirstName = rdr.IsDBNull(indexFirstName))? String.Empty: rdr.GetString(indexFirstName); 
replace每个属性types的默认值(当为空值)…
此方法依赖于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"]; } 
您可以使用条件运算符:
 employee.FirstName = sqlreader["indexFirstName"] != DBNull.Value ? sqlreader[indexFirstName].ToString() : ""; 
你也可以检查这个
 if(null !=x && x.HasRows) { ....}