В чем смысл DBNull?

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

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

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

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

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

5 ответов


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

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


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

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

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

int? x = null;

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

  • DBNull терпит неудачу в терминах null-коалесцирования;value ?? defaultValue не работает, если значение DBNull
  • DBNull.Value не может использоваться в необязательных параметрах, так как это не константа
  • семантика выполнения DBNull идентичны семантика null; в частности, DBNull фактически составляет DBNull - так это не выполните задание представления SQL semantic
  • он часто заставляет значения типа значения быть в коробке, так как он использует object
  • если вам нужно проверить для DBNull, вы могли бы также протестировать для just null
  • это вызывает огромные проблемы для таких вещей, как command-parameters, с очень глупым поведением, если параметр имеет null значение не отправляется... Ну, вот идея: если вам не нужен параметр - не добавлять его в коллекцию параметров
  • каждый ОРМ, о котором я могу думать, отлично работает без любой нужно или использовать DBNull, за исключением как дополнительная досада при разговоре с ADO.NET код
  • только даже отдаленно убедительный аргумент у меня когда-нибудь видели, чтобы оправдать существование такого значения в DataTable, при передаче значений для создания новой строки; a null означает "использовать значение по умолчанию", a DBNull является явно нулевым-откровенно говоря, этот API мог бы иметь конкретное лечение для этого случая-мнимое DataRow.DefaultValue например, было бы намного лучше, чем вводить DBNull.Value это заражает обширные полосы кода без причины.

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

    не думаю, что все согласны с тем, что это "очевидная" вещь. Многие разработчики делают не см. значение в этой нечетной морщине на BCL.

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

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

    резюме:

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


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


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

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

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

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


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

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

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

    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.Значение, оно будет использовать это и echo Значение dbnull.Значение.

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

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