在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"];