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) { ....}