Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the point of DBNull?

In .NET there is the null reference, which is used everywhere to denote that an object reference is empty, and then there is the DBNull, which is used by database drivers (and few others) to denote... pretty much the same thing. Naturally, this creates a lot of confusion and conversion routines have to be churned out, etc.

So why did the original .NET authors decide to make this? To me it makes no sense. Their documentation makes no sense either:

The DBNull class represents a nonexistent value. In a database, for example, a column in a row of a table might not contain any data whatsoever. That is, the column is considered to not exist at all instead of merely not having a value. A DBNull object represents the nonexistent column. Additionally, COM interop uses the DBNull class to distinguish between a VT_NULL variant, which indicates a nonexistent value, and a VT_EMPTY variant, which indicates an unspecified value.

What's this crap about a "column not existing"? A column exists, it just doesn't have a value for the particular row. If it didn't exist, I'd get an exception trying to access the specific cell, not a DBNull! I can understand the need to differentiate between VT_NULL and VT_EMPTY, but then why not make a COMEmpty class instead? That would be a much neater fit in the whole .NET framework.

Am I missing something? Can anyone shed some light why DBNull was invented and what problems it helps to solve?

like image 968
Vilx- Avatar asked Dec 20 '10 10:12

Vilx-


People also ask

What is DBNull in SQL Server?

DBNull is a singleton class, which means only this instance of this class can exist. If a database field has missing data, you can use the DBNull. Value property to explicitly assign a DBNull object value to the field. However, most data providers do this automatically.

What is DBNull value in VB net?

DbNull is used to denote the fact that a variable contains a missing or nonexistent value, and it is used primarily in the context of database field values.

Is DBNull or empty C#?

Empty; Please do not confuse the notion of null in C# language with a DBNull object. In an object-oriented programming language, null means the absence of a reference to an object, whereas DBNull represents an uninitialized field or nonexistent database column.

What does Object Cannot be cast from DBNull to other types mean?

Accept Solution Reject Solution. The error is pretty explicit: "Object cannot be cast from DBNull to other types" Your database field can (and does) contain SQL NULL values - and when they are returned via a query, the value is a specific code which represents this in a way that your code can check and use: DBNull. ...


2 Answers

I'm going to disagree with the trend here. I'll go on record:

I do not agree that DBNull serves any useful purpose; it adds unnecessary confusion, while contributing virtually no value.

The argument is often put forward that null is an invalid reference, and that DBNull is a null object pattern; neither is true. For example:

int? x = null; 

this is not an "invalid reference"; it is a null value. Indeed null means whatever you want it to mean, and frankly I have absolutely no problem working with values that may be null (indeed, even in SQL we need to correctly work with null - nothing changes here). Equally, the "null object pattern" only makes sense if you are actually treating it as an object in OOP terms, but if we have a value that can be "our value, or a DBNull" then it must be object, so we can't be doing anything useful with it.

There are so many bad things with DBNull:

  • it forces you to work with object, since only object can hold DBNull or another value
  • there is no real difference between "could be a value or DBNull" vs "could be a value or null"
  • the argument that it stems from 1.1 (pre-nullable-types) is meaningless; we could use null perfectly well in 1.1
  • most APIs have "is it null?" methods, for example DBDataReader.IsDBNull or DataRow.IsNull - neither of which actually require DBNull to exist in terms of the API
  • DBNull fails in terms of null-coalescing; value ?? defaultValue doesn't work if the value is DBNull
  • DBNull.Value can't be used in optional parameters, since it isn't a constant
  • the runtime semantics of DBNull are identical to the semantics of null; in particular, DBNull actually equals DBNull - so it does not do the job of representing the SQL semantic
  • it often forces value-type values to be boxed since it over-uses object
  • if you need to test for DBNull, you might as well have tested for just null
  • it causes huge problems for things like command-parameters, with a very silly behaviour that if a parameter has a null value it isn't sent... well, here's an idea: if you don't want a parameter sent - don't add it to the parameters collection
  • every ORM I can think of works perfectly well without any need or use of DBNull, except as an extra nuisance when talking to the ADO.NET code

The only even remotely compelling argument I've ever seen to justify the existence of such a value is in DataTable, when passing in values to create a new row; a null means "use the default", a DBNull is explicitly a null - frankly this API could have had a specific treatment for this case - an imaginary DataRow.DefaultValue for example would be much better than introducing a DBNull.Value that infects vast swathes of code for no reason.

Equally, the ExecuteScalar scenario is... tenuous at best; if you are executing a scalar method, you expect a result. In the scenario where there are no rows, returning null doesn't seem too terrible. If you absolutely need to disambiguate between "no rows" and "one single null returned", there's the reader API.

This ship has sailed long ago, and it is far far too late to fix it. But! Please do not think that everyone agrees that this is an "obvious" thing. Many developers do not see value in this odd wrinkle on the BCL.

I actually wonder if all of this stems from two things:

  • having to use the word Nothing instead of something involving "null" in VB
  • being able to us the if(value is DBNull) syntax which "looks just like SQL", rather than the oh-so-tricky if(value==null)

Summary:

Having 3 options (null, DBNull, or an actual value) is only useful if there is a genuine example where you need to disambiguate between 3 different cases. I have yet to see an occasion where I need to represent two different "null" states, so DBNull is entirely redundant given that null already exists and has much better language and runtime support.

like image 149
Marc Gravell Avatar answered Oct 11 '22 04:10

Marc Gravell


The point is that in certain situations there is a difference between a database value being null and a .NET Null.

For example. If you using ExecuteScalar (which returns the first column of the first row in the result set) and you get a null back that means that the SQL executed did not return any values. If you get DBNull back it means a value was returned by the SQL and it was NULL. You need to be able to tell the difference.

like image 35
Colin Mackay Avatar answered Oct 11 '22 03:10

Colin Mackay