Jaka jest różnica między null i System.DBNull.Value?

92

Czy jest jakaś różnica między null i System.DBNull.Value? Jeśli tak, co to jest?

Zauważyłem teraz to zachowanie -

while (rdr.Read())
{
    if (rdr["Id"] != null) //if (rdr["Id"] != System.DBNull.Value)  
    {
        int x = Convert.ToInt32(rdr["Id"]);
    }
}

A ja pobierania danych z bazy danych przy użyciu DataReader SQL, choć nie ma wartości zwracane if(rdr["Id"] != null)powrócił truei ostatecznie zwrócił wyjątek odlewania null jako całkowitą.

Ale to, jeśli używam if (rdr["Id"] != System.DBNull.Value)zwrotów false.

Jaka jest różnica między wartością null a System.DBNull.Value?

pavanred
źródło
Cóż, nie są ze sobą spokrewnieni. Jedna to statyczna instancja klasy w System.Data, a druga to specjalna wartość oznaczająca brak desygnatu. Nie mają ze sobą nic wspólnego. Czy możesz wyjaśnić, w czym jesteś zdezorientowany? Czy Twoje prawdziwe pytanie brzmi: „dlaczego robić DataRowsi DataReaderswkładać DBNull.Valuew siebie zamiast null?”
mqp
Cóż, na początku nie było, ale po nauczeniu się z tego, co powiedziałeś, jestem ciekawy. Czy możesz mi powiedzieć, dlaczego DataRows i DataReaders umieszczają DBNull.Value w sobie zamiast null?
pavaned
Sam nie jestem pewien. Oto jedna odpowiedź: stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull/… Możliwe jest również, że zanim typy wartości nullable były dostępne w C #, byłoby to bardziej kłopotliwe null.
mqp
1
Miałem tutaj odpowiedź, ale zdałem sobie sprawę, że bardziej pasuje do stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull - więc przeniosłem ją
Marc Gravell

Odpowiedzi:

117

Cóż, nullnie jest to żaden typ. Jest to raczej nieprawidłowe odniesienie.

Jednak System.DbNull.Valuejest prawidłowym odwołaniem do wystąpienia System.DbNull( System.DbNulljest singletonem i System.DbNull.Valuezawiera odniesienie do pojedynczego wystąpienia tej klasy), które reprezentuje nieistniejące * wartości w bazie danych.

* Normalnie powiedzielibyśmy null, ale nie chcę mylić problemu.

Tak więc istnieje między nimi duża różnica pojęciowa. Słowo kluczowe nullreprezentuje nieprawidłowe odniesienie. Klasa System.DbNullreprezentuje nieistniejącą wartość w polu bazy danych. Generalnie powinniśmy unikać używania tego samego (w tym przypadku null) do reprezentowania dwóch bardzo różnych koncepcji (w tym przypadku nieprawidłowe odwołanie w porównaniu z nieistniejącą wartością w polu bazy danych).

Należy pamiętać, że dlatego wiele osób w ogóle opowiada się za użyciem wzorca obiektu zerowego , który jest dokładnie tym System.DbNullprzykładem.

Jason
źródło
43
+1 Praktyczny przykład: jeśli używasz IDbCommand.ExecuteScalar(), może zwrócić wartość null (brak zwróconych rekordów) lub DbNull(pierwsza kolumna w pierwszym rekordzie to „nieistniejąca wartość”). Bez DbNullCiebie nie byłbyś w stanie odróżnić jednego od drugiego.
C.Evenhuis,
Zdecydowanie polecam używanie języka, który zabrania używania Null i robi to za absolutnie zerową opłatą dodatkową. życie jest zbyt krótkie dla "wzorca obiektu zerowego"
nicolas
3
Puste odniesienie jest całkowicie poprawne. ☺
IllidanS4 obsługuje Monikę
@ C.Evenhuis Cóż, jest jeszcze jedna częsta rada: funkcja powinna zwracać tylko jeden typ wartości. Dlatego ludzie wolą dobrze napisany kod TypeScript. „Jaki jest stan wykonania” różni się od „Jaki jest wynik obliczeń”. To znaczy. mogliby zdecydować się zaimplementować tę funkcję w inny sposób (może parametr out lub obiekt podobny do obiektów odpowiedzi na żądanie HTTP). Jasne, jest to niezbyt pożądana komplikacja, ale gdyby to zrobili, może zamiast DbNull można użyć null.
klenium
21

Z dokumentacji klasy DBNull :

Nie należy mylić pojęcia null w języku programowania obiektowego z obiektem DBNull. W języku programowania obiektowego wartość null oznacza brak odniesienia do obiektu. DBNull reprezentuje niezainicjowany wariant lub nieistniejącą kolumnę bazy danych.

Heinzi
źródło
11

DBNull.Value jest irytujące.

Używam metod statycznych, które sprawdzają, czy to DBNull, a następnie zwracają wartość.

SqlDataReader r = ...;
String firstName = getString(r[COL_Firstname]);

private static String getString(Object o) {
   if (o == DBNull.Value) return null;
   return (String) o;
}

Ponadto, podczas wstawiania wartości do DataRow, nie możesz użyć „null”, musisz użyć DBNull.Value.

Dwie reprezentacje „null” to zły projekt bez widocznych korzyści.

Odraza
źródło
2
Uczucie wstrętu re my zakładowym: Twoja ostatnia wypowiedź jest zmyślone tylko przez ironii pokazuje się tutaj, aby przeczytać i dowiedzieć się nazwy użytkownika jest „wstręt”
Iofacture
5

DBNull.Value jest tym, co dostawcy bazy danych .NET zwracają, aby reprezentować pusty wpis w bazie danych. DBNull.Value nie ma wartości null i porównania z wartością null dla wartości kolumn pobranych z wiersza bazy danych nie będą działać, należy zawsze porównać z wartością DBNull.Value.

http://msdn.microsoft.com/en-us/library/system.dbnull.value.aspx

James Michael Hare
źródło
ps Należy również użyć DBNull.Value do przekazania parametru zerowego do bazy danych, w przeciwnym razie może zostać zinterpretowane jako nieprzekazany parametr.
James Michael Hare
1
DBNull nie jest „tym, co zwraca baza danych” - jest to po prostu sposób interpretacji ADO.NET; osobiście nie jestem pewien, czy ta interpretacja jest bardzo cenna
Marc Gravell
@MarcGravell Tak, Marc, masz rację. Źle to sformułowałem. ASP.NET przekłada wartość kolumny bazy zerowej do DBNull.Value
James Michael Hare
3

DataRow ma wywoływaną metodę, IsNull()której można użyć do przetestowania kolumny, jeśli ma wartość null - w odniesieniu do wartości null widzianej przez bazę danych.

DataRow["col"]==nullzawsze będzie false.

posługiwać się

DataRow r;
if (r.IsNull("col")) ...

zamiast.

Daniel Mošmondor
źródło
3

Null jest podobne do wskaźnika zerowego w C ++ . Jest to więc odniesienie, które nie wskazuje na żadną wartość .

DBNull.Valuejest zupełnie inna i jest stałą, która jest zwracana, gdy wartość pola zawiera NULL.

Aliostad
źródło