在C#中处理DBNull

有没有更好的/更干净的方法来做到这一点?

int stockvalue = 0; if (!Convert.IsDBNull(reader["StockValue"])) stockvalue = (int)reader["StockValue"]; 

最短的(恕我直言)是:

 int stockvalue = (reader["StockValue"] as int?) ?? 0; 

说明:

  • 如果reader [“StockValue”]的types是int ,则返回值,“??” 运算符将返回结果
  • 如果reader [“StockValue”]不是inttypes(例如DBNull),则返回null,而“??” 运算符将返回值0(零)。

我处理这个的方式是

 int? stockvalue = reader["StockValue"] as int?; 

很简单,干净,一条线。 如果由于某种原因,我绝对不能有一个空值(我发现通常不好的推理,因为我宁愿知道一个值是否有意义,或者如果它是一个原始types单位化)我会这样做:

 int stockvalue = (reader["StockValue"] as int?).GetValueOrDefault(-1); 
 int? stockvalue = (int?)(!Convert.IsDBNull(result) ? result : null); 

一个可能的解决scheme,以确保DBNull传递到您的代码。 对于我们的团队来说,作为一个最佳实践,我们尝试并且不允许数据库中的NULL列,除非它真的需要。 在编码方面有更多的开销来处理它,有时只是重新思考这个问题,所以它不是必需的。

我前几天写了一个扩展方法。 通过使用它,你可以做到:

 int? stockvalue = reader.GetValue<int?>("StockValue"); 

这里是扩展方法(修改以适应您的需求):

 public static class ReaderHelper { public static bool IsNullableType(Type valueType) { return (valueType.IsGenericType && valueType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))); } public static T GetValue<T>(this IDataReader reader, string columnName) { object value = reader[columnName]; Type valueType = typeof(T); if (value != DBNull.Value) { if (!IsNullableType(valueType)) { return (T)Convert.ChangeType(value, valueType); } else { NullableConverter nc = new NullableConverter(valueType); return (T)Convert.ChangeType(value, nc.UnderlyingType); } } return default(T); } } 

是的,你可以使用int? 这样你可以有一个默认值null而不是0.由于stockvalue的结果可能是0,不会混淆数据库是0还是null。 例如像这样(可以为空),我们有一个默认的初始值-1来表示没有赋值。 就我个人而言,我认为这有点危险,因为如果您忘记将其设置为-1,则会出现数据损坏问题,这些问题确实难以追查。

http://msdn.microsoft.com/en-us/library/2cf62fcy(VS.80).aspx

 int? stockvalue = null; if (!Convert.IsDBNull(reader["StockValue"])) stockvalue = (int)reader["StockValue"]; //Then you can check if(stockValue.HasValue) { // do something here. } 

尽pipe引用reader["StockValue"]很方便,但效率不高。 它也不是强types的,因为它返回typesobject

相反,在你的代码中,做这样的事情:

 int stockValueOrdinal = reader.GetOrdinal("StockValue"); int? stockValue = reader.IsDbNull(stockValueOrdinal) ? null : reader.GetInt32(stockValueOrdinal); 

当然,最好一次性得到所有的序号,然后在整个代码中使用它们。

 int stockvalue = reader["StockValue"] != DbNull.Value ? Convert.ToInt32(reader["StockValue"]) : 0; 

这是一种方法。

 int stockvalue = Convert.IsDbNull(reader["StockValue"]) ? 0 : (int)reader["StockValue"]; 

你也可以使用TryParse

 int stockvalue = 0 Int32.TryParse(reader["StockValue"].ToString(), out stockvalue); 

让我们知道哪个方法适合你

您可以直接在您的数据库查询中进行此转换,从而避免特殊情况。

但是我不会称之为'更干净',除非你可以在你的代码中一致地使用这个表单,因为你会通过从DB中返回0而不是NULL来丢失信息。

使用Nullable<int>types… int? 简而言之

不是真的。 你可以把它封装在一个方法中:

 public int getDBIntValue(object value, int defaultValue) { if (!Convert.IsDBNull(value)) { return (int)value; } else { return defaultValue; } 

并像这样调用它:

 stockVaue = getDBIntVaue(reader["StockValue"], 0); 

或者你可以在查询中使用coalesce来强制返回的值是非空的。

根据收到的评论编辑 – 更正的哑代码错误。

我的项目中有两个扩展方法:

  public static T GetValueSafe<T>(this IDataReader dataReader, string columnName, Func<IDataReader, int, T> valueExtractor) where T : class { T value; if (dataReader.TryGetValueSafe(columnName, valueExtractor, out value)) { return value; } return null; } public static bool TryGetValueSafe<T>(this IDataReader dataReader, string columnName, Func<IDataReader, int, T> valueExtractor, out T value) { int ordinal = dataReader.GetOrdinal(columnName); if (!dataReader.IsDBNull(ordinal)) { // Get value. value = valueExtractor.Invoke(dataReader, ordinal); return true; } value = default(T); return false; } 

用法可以是这样的:

 string companyName = dataReader.GetValueSafe("CompanyName", (reader, ordinal) => reader.GetString(ordinal)); 
 int? stockValue = reader["StockValue"] == null || reader["StockValue"] == DBNull.Value ? null : (int?)reader["StockValue"];