Какой смысл в DBNull?

В.NET есть null ссылка, которая используется везде, чтобы обозначить, что ссылка на объект пуста, а затем есть DBNull, который используется драйверами базы данных (и немногими другими), чтобы обозначить... почти то же самое. Естественно, это создает много путаницы, и необходимо преобразовать процедуры преобразования и т. Д.

Так почему же авторы.NET решили сделать это? Для меня это не имеет смысла. Их документация также не имеет смысла:

Класс DBNull представляет несуществующее значение. Например, в базе данных столбец в строке таблицы может не содержать никаких данных. То есть считается, что столбец вообще не существует, а просто не имеет значения. Объект DBNull представляет несуществующий столбец. Кроме того, COM-взаимодействие использует класс DBNull, чтобы различать вариант VT_NULL, который указывает на несуществующее значение, и вариант VT_EMPTY, который указывает неуказанное значение.

Что это за хрень про "столбец не существует"? Столбец существует, у него просто нет значения для конкретной строки. Если бы его не было, я бы получил исключение, пытаясь получить доступ к определенной ячейке, а не DBNull! Я могу понять необходимость различать VT_NULL а также VT_EMPTYно почему бы не сделать COMEmpty класс вместо? Это было бы гораздо лучше вписаться во всю среду.NET.

Я что-то пропустил? Может кто-нибудь пролить свет почему DBNull был изобретен и какие проблемы это помогает решить?

5 ответов

Решение

Дело в том, что в определенных ситуациях существует разница между значением базы данных, равным NULL, и значением.NET, равным NULL.

Например. Если вы используете ExecuteScalar (который возвращает первый столбец первой строки в наборе результатов) и вы получаете нулевое значение, это означает, что выполненный SQL не возвращал никаких значений. Если вы возвращаете DBNull, это означает, что значение было возвращено SQL, и оно было NULL. Вы должны быть в состоянии отличить.

Я собираюсь не согласиться с тенденцией здесь. Я пойду на запись:

Я не согласна что DBNull служит любой полезной цели; это добавляет ненужную путаницу, внося практически никакой ценности.

Аргумент часто выдвигается, что null неверная ссылка, и это DBNull шаблон нулевого объекта; ни то, ни другое Например:

int? x = null;

это не "недействительная ссылка"; это null значение. В самом деле null означает, что вы хотите, чтобы это значило, и, честно говоря, у меня нет абсолютно никаких проблем с работой со значениями, которые могут быть null (действительно, даже в SQL нам нужно правильно работать с null - здесь ничего не меняется). Точно так же "шаблон нулевого объекта" имеет смысл, только если вы фактически рассматриваете его как объект в терминах ООП, но если у нас есть значение, которое может быть "нашим значением или DBNull "тогда это должно быть object поэтому мы не можем делать с этим ничего полезного.

Есть так много плохих вещей с DBNull:

  • это заставляет вас работать с object, так как только object может держать DBNull или другое значение
  • нет никакой разницы между "может быть значением или DBNull "против" может быть значением или null "
  • аргумент, что это происходит из 1.1 (pre-nullable-types), не имеет смысла; мы могли бы использовать null отлично в 1.1
  • у большинства API есть "это нуль?" методы, например DBDataReader.IsDBNull или же DataRow.IsNull - ни один из которых на самом деле не требует DBNull существовать с точки зрения API
  • DBNull терпит неудачу с точки зрения нуль-слияния; value ?? defaultValue не работает, если значение DBNull
  • DBNull.Value не может использоваться в необязательных параметрах, так как это не константа
  • семантика времени выполнения DBNull идентичны семантике null; особенно, DBNull на самом деле равен DBNull - поэтому он не выполняет работу по представлению семантики SQL
  • это часто вынуждает упаковывать значения типа значения, так как оно чрезмерно использует object
  • если вам нужно проверить DBNull, вы могли бы также проверить только null
  • это вызывает огромные проблемы для таких вещей, как параметры команды, с очень глупым поведением, что если параметр имеет null значение это не отправлено... хорошо, вот идея: если вы не хотите, чтобы параметр был отправлен - не добавляйте его в коллекцию параметров
  • каждый ОРМ, который я могу придумать, прекрасно работает без необходимости или использования DBNull, кроме как дополнительное неудобство при разговоре с кодом ADO.NET

Единственный даже отдаленно убедительный аргумент, который я когда- либо видел, чтобы оправдать существование такой ценности, заключается в DataTable при передаче значений для создания новой строки; null означает "использовать по умолчанию", DBNull является явно нулевым - честно говоря, этот API мог бы иметь специальную обработку для этого случая - мнимый DataRow.DefaultValue например, было бы намного лучше, чем введение DBNull.Value это заражает обширные участки кода без причины.

В равной степени ExecuteScalar сценарий... в лучшем случае незначителен; если вы выполняете скалярный метод, вы ожидаете результата. В сценарии, где нет строк, возвращается null не кажется слишком страшным. Если вам абсолютно необходимо устранить неоднозначность между "без строк" ​​и "возвращен один ноль", есть API для чтения.

Этот корабль уже давно отплыл, и уже слишком поздно его чинить. Но! Пожалуйста, не думайте, что все согласны с тем, что это "очевидная" вещь. Многие разработчики не видят ценности в этой странной складке на BCL.

Мне действительно интересно, если все это проистекает из двух вещей:

  • приходится использовать слово Nothing вместо чего-то, связанного с "нулем" в VB
  • будучи в состоянии нам if(value is DBNull) синтаксис, который "выглядит так же, как SQL", а не такой уж сложный if(value==null)

Резюме:

Имея 3 варианта (null, DBNull (или фактическое значение) полезно только в том случае, если имеется подлинный пример, в котором вам необходимо устранить неоднозначность между 3 различными случаями. Мне еще предстоит увидеть случай, когда мне нужно представить два разных "нулевых" состояния, поэтому DBNull полностью излишним, учитывая, что null уже существует и имеет гораздо лучшую поддержку языка и времени выполнения.

DbNull представляет собой ящик без содержимого; null указывает на несуществование коробки.

Вы используете DBNull для отсутствующих данных. Нуль в языке.NET означает, что для объекта / переменной нет указателя.

DBNull отсутствует данные: http://msdn.microsoft.com/en-us/library/system.dbnull.value.aspx

Влияние недостающих данных на статистику:

http://en.wikipedia.org/wiki/Missing_values

Есть некоторые различия между нулем CLR и DBNull. Во-первых, нуль в реляционных базах данных имеет различную семантику "равно": нуль не равен нулю. CLR NULL равно нулю.

Но я подозреваю, что основная причина заключается в том, как значения параметров по умолчанию работают на сервере SQL, и в реализации поставщика.

Чтобы увидеть разницу, создайте процедуру с параметром, который имеет значение по умолчанию:

CREATE PROC [Echo] @s varchar(MAX) = 'hello'
AS
    SELECT @s [Echo]

Хорошо структурированный код DAL должен отделять создание команды от использования (чтобы разрешить многократное использование одной и той же команды, например, для эффективного вызова хранимой процедуры много раз). Напишите метод, который возвращает SqlCommand, представляющий вышеуказанную процедуру:

SqlCommand GetEchoProc()
{
    var cmd = new SqlCommand("Echo");
    cmd.Parameters.Add("@s", SqlDbType.VarChar);
    return cmd;
}

Если вы теперь вызываете команду без установки параметра @s или устанавливаете ее значение (CLR) null, она будет использовать значение по умолчанию 'hello'. Если, с другой стороны, вы установите значение параметра в DBNull.Value, оно будет использовать его и отобразит DbNull.Value.

Поскольку есть два разных результата, использующих значение CLR null или базу данных null в качестве значения параметра, вы не можете представить оба случая только с одним из них. Если бы CLR null был единственным, он должен работать так же, как DBNull.Value сегодня. Один из способов указать поставщику "Я хочу использовать значение по умолчанию" может состоять в том, чтобы вообще не объявлять параметр (параметр со значением по умолчанию, конечно, имеет смысл описать как "необязательный параметр"), но в Сценарий, в котором объект команды кэшируется и используется повторно, приводит к удалению и повторному добавлению параметра.

Я не уверен, думаю ли я, что DBNull была хорошей идеей или нет, но многие люди не знают о вещах, которые я упомянул здесь, поэтому я решил, что стоит упомянуть.

Чтобы ответить на ваш вопрос, вы должны подумать, почему DBNull вообще существует?

DBNull необходим в узком случае использования. В противном случае это не так. Большинству людей DBNull никогда не нужен. Я никогда не позволяю вводить их в хранилища данных, которые я разрабатываю. У меня ВСЕГДА есть значение, поэтому мои данные никогда не имеют значения "", я всегда выбираю значимый тип "значение по умолчанию", и мне никогда не нужно делать эту абсурдную двойную проверку всего дважды в коде, один раз для - это объект null, и снова, потому что это DBNull, прежде чем я приведу свой объект к моему фактическому типу данных (например, Int и т. д.).

DBNull необходим в одном случае, который может вам понадобиться... если вы используете некоторые функции статистики SQL (например: медиана, среднее значение) ... они обрабатывают DBNull специально... посмотрите эти документы... некоторые функции не включают DBNull в общем количестве для статистики... например: (87 сумм / 127 всего) vs. (87 сумм / 117 итогов) .. разница в том, что 10 из этих значений столбца были DBNull... вы можете видеть, что это изменится результат статистики.

Мне не нужно проектировать свои базы данных с помощью DBNull. Если бы мне когда-либо понадобились статистические результаты, я бы явно изобрел или добавил столбец, такой как UserDidProvideValue, для этого одного элемента, который требует какой-то особой обработки, потому что он не существует (например, мое общее количество 117 было бы суммой полей, отмеченных UserDidProvideValue=true) ... ха-ха, лол - в моей следующей жизни в качестве правителя Вселенной, лол - DBNull никогда бы не позволили выйти из области SQL... весь мир программирования теперь обязан проверять все дважды... когда Было ли у вас когда-нибудь мобильное приложение, настольное приложение или веб-сайт, которым нужно было иметь "нулевое" целое число? - Никогда...

Другие вопросы по тегам