Есть ли лучший/более чистый способ сделать это?
int stockvalue = 0;
if (!Convert.IsDBNull(reader["StockValue"]))
stockvalue = (int)reader["StockValue"];
Есть ли лучший/более чистый способ сделать это?
int stockvalue = 0;
if (!Convert.IsDBNull(reader["StockValue"]))
stockvalue = (int)reader["StockValue"];
Самый короткий (IMHO):
int stockvalue = (reader["StockValue"] as int?) ?? 0;
Пояснение:
Как я справляюсь с этим,
int? stockvalue = reader["StockValue"] as int?;
Очень простая, чистая и одна строка. Если по какой-то причине я абсолютно не могу иметь нулевое значение (которое обычно я нахожу в непринужденной аргументации, так как я предпочел бы знать, имеет ли значение значение или был ли он унифицирован для примитивного типа), я бы сделал:
int stockvalue = (reader["StockValue"] as int?).GetValueOrDefault(-1);
int? stockvalue = (int?)(!Convert.IsDBNull(result) ? result : null);
Одно из возможных решений, позволяющее гарантировать, что 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. Так как результат запаса может потенциально равняться 0, не возникает путаницы в отношении того, была ли база данных 0 или нулевой. Например, как это (pre nullable), мы имели инициализацию по умолчанию -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.
}
В то время как удобно ссылаться на reader["StockValue"]
, это не очень эффективно. Он также не сильно типизирован, так как он возвращает тип object
.
Вместо этого в вашем коде сделайте что-то вроде этого:
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-запросе, тем самым избегая особого случая alltogether.
Но я бы не назвал это "чище", если вы не можете последовательно использовать эту форму в своем коде, так как вы потеряете информацию, вернув "0" вместо NULL из базы данных.
используйте тип Nullable<int>
... 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"];