views:

620

answers:

4

If .NET 2.0 nullable types was there from version 1, will DBNull.Value not be needed in the first place?

Or RDBMS's null has no bearing with .NET's null? That is DBNull.Value will still be needed anyhow, regardless of .NET version 1 already have nullable types.

+5  A: 

null and DBNull.Value are two different things in any .NET version.

For example:

public string CustomerName(int Id)
{
   SqlCommand cmd = new SqlCommand(string.Format("SELECT Name FROM Customer WHERE id = {0}", custId), conn);

   object result = cmd.ExecuteScalar();

   if (result == null)
      return "Customer not found";

   if (result == System.DBNull.Value)
      return "Customer found but name is null";

   return (string) result;
}
Mitch Wheat
Excellent example.
Sergio Acosta
in restrospection, could they design SqlCommand to return null instead of DBNull.Value if nullable types was in version 1 then?
Hao
@Hao: and how would they distinguish the 2 cases in my example?
Mitch Wheat
maybe they find that they can "overload" the function to return two different types of nulls (.NET's null and DB's null [DBNull.value]) because nullable types wasn't in place then
Hao
@Hao: ? not sure what you mean?
Mitch Wheat
This is just a matter of design. They could just return null for an database null and throw an exception if no row exists or return a tuple with value and number of found rows (actually ExecuteScalar() just returns the first column of the first row of the query result) or use an out parameter.
Daniel Brückner
Just like with variable.TryParse, you must have a formal way to return two results. One, for the conversion if it is successful, and two, where to put the result of the function. That's how i think they would most likely implement ExecuteScalar if nullable types was there from the beginning.
Hao
@danbruc: nice answer, if i can only upvote comments
Hao
Overloading a function with different return type is not possible in .NET. And even if it would be possible you cannot deciede what method (with it's return type) to call based on the result of the call.
Daniel Brückner
@Mitch Wheat: I think if db's null was mapped to .net's native null(not DBNull.Value), i think they would not design ExecuteScalar to indicate null for "Customer not found", they would most likely put an out parameter to indicate foundness(bad english). Just like with TryParse method
Hao
I will put the comment into my answer for one upvote ... :D
Daniel Brückner
Would the downvoter please leave a comment as to why. Thanks.
Mitch Wheat
hmm.. reminds me of C language's atoi function :-) braindead implementation,it returns 0 if it encounters non-numeric character. atoi("0") == 0, atoi("hello") == 0. cannot indicate if conversion was successful or not, they should have put an extra parameter to indicate if conversion was successful
Hao
I voted it done because I do not think it captures the essence. This is illustrates just an design decision for the method. The difference between the two nulls lies in the semantic. I just tested it and DBNull does NOT behave as it should; DBNull.Value == DBNull.Value is true but should be false.
Daniel Brückner
@danbruc: why should "DBNull.Value == DBNull.Value is true but should be false"?
Mitch Wheat
@danbruc: so you voted me down because of a MS design decision? sheesh! ;)
Mitch Wheat
@danbruc: all things being equal by your own reasoning, DBNull.Value == DBNull.Value should equal null na dnot false.
Mitch Wheat
+7  A: 

Nullable types in .NET allow the variable in question to actually be null. DBNull is a way to say "in another environment, this value was considered to be null". Since we need a way do differentiate between actually null - or "natively" null, as in native to our current runtime - and null in another system we communicate with, nullable types and DBNull serve completely different purposes.

Rex M
True and well said, though I think we'd be hard pressed to find a case where ADO.NET could not simply return null instead of DBNull. In retrospect, whether or not DBNull was a good idea is arguable. One can only speculate how Nullable<T> would have influenced the design if it were in .NET 1.0.
binarycoder
@binarycoder certainly ADO.NET *could* return null, but that would appropriate our beloved null for something much more specific. I am not sure how we would benefit from treating the database and the application like one environment that completely share types and values.
Rex M
+1 for "in another environment"
Hao
+1  A: 

I do not really agree to this.

Nullable types in .NET allow the variable in question to actually be null. DBNull is a way to say "in another environment, this value was considered to be null". Since we need a way do differentiate between actually null - or "natively" null, as in native to our current runtime - and null in another system we communicate with, nullable types and DBNull serve completely different purposes.

This distinction is only required if you do not know if your local variable has allready been fetched from the database. If you know that the variable has been fetched from the database it would be okay to identify null and DBNull.

But the difference is that null in programming languages signals the absence of a value and null == null is true. In databases the null indicates something more like an unknown value. Therefore null == null is false in databases; null equals nothing at all because you cannot tell for an unknown value if it equals another unknown value. I am not sure if DBNull is implemented this way and DBNull.Value == DBNull.Value evaluates to false.

EDIT

I just tested it and DBNull does not behave as exspected. DBNull.Value == DBNull.Value evaluates to true but should yield false with the semantic of the database null.

Daniel Brückner
@dan actually I think we are saying nearly the same thing.
Rex M
We are. You could do with just one type of null but there are some reasons in current enviroments to have more than one.
Daniel Brückner
+3  A: 

If System.Data.DataSetExtensions.dll is anything to go by, I'm guessing that DBNull.Value probably wouldn't exist if nullable value types had been available at the time.

Using that library's extension methods on a DataRow that has a "foo" column set to DBNull.Value, you get...

row.Field<int?>("foo");  // returns a nullable int set to null
row.Field<int>("foo");   // throws an InvalidCastException

This is, of course, incredibly convenient when combined with the C# ?? operator, when you want to provide a default value in place of a database null. Personally, I wasted no time implementing similar extension methods on IDataReader/IDataRecord.

Joel Mueller