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