Подтвердить что ты не робот

В чем смысл DBNull?

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

int? x = null;

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

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

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

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

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

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

На самом деле мне интересно, все ли это связано с двумя вещами:

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

Резюме:

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

Ответ 3

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

Ответ 5

Существуют некоторые различия между CLR null и DBNull. Во-первых, null в реляционных базах данных имеет разную семантику "равно": null не равен нулю. Значение 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, оно будет использовать это и echo DbNull.Value.

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

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