Reputation: 63
I have come across a scenario that I did not expect and need help answering. Our current system makes calls to SQL stored procs and as such creates SQL commands, adds the parameters and adds the values of those parameters...say for an Insert.
We had code like what is below...
cmd.Parameters.Add("@MyTimestamp", SqlDbType.DateTime)
If MyObject.MyTimestamp <> Nothing Then
cmd.Parameters.Item("@MyTimestamp").Value = MyObject.MyTimestamp
Else
cmd.Parameters.Item("@MyTimestamp").Value = Nothing
End If
Now, when I first saw this I was a little surprised that the MyObject.MyTimestamp ever evaluated to Nothing, but it had been there for years with no issue. During a clean-up effort the code to add a parameter and set its value was combined and as such the code above became...
cmd.Parameters.Add("@MyTimestamp", SqlDbType.DateTime).Value = If(MyObject.MyTimestamp <> Nothing, MyObject.MyTimestamp, Nothing)
To me, this looked equivalent to what the code was doing originally, however that is not what was found during testing. While testing I received a SqlTypeException:
SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
That is because using the If Operator evaluated the MyObject.MyTimestamp as not being Nothing, which it isn't Nothing it is DateTime.MinValue and it tried to insert it into sql and it blew up. The way the original code was written evaluates the same Timestamp as being Nothing (not sure how/why) and does the false part. So my question is what is the difference and should I be concerned about other datatypes...?
Upvotes: 4
Views: 149
Reputation: 69789
Remembering (as I often don't) that Nothing
is not equivalent to null
in C#, but more like Default(T)
, the following does not check if MyObject.MyTimestamp has been set:
MyObject.MyTimestamp <> Nothing
But is acutally checking if it is the default datetime (DateTime.MinValue), which it presumably always is.
In addition, when you use:
If(MyObject.MyTimestamp <> Nothing, MyObject.MyTimestamp, Nothing)
The two return types (MyObject.MyTimestamp
, Nothing
) have to be of the same type, so since the compiler knows MyObject.Timestamp
should be a datetime, it converts nothing to a default datetime.
When you use this, however:
If MyObject.MyTimestamp <> Nothing Then
cmd.Parameters.Item("@MyTimestamp").Value = MyObject.MyTimestamp
Else
cmd.Parameters.Item("@MyTimestamp").Value = Nothing
End If
It recognises that the parameter for "@MyTimestamp"
is of the type SqlDbType.DateTime
, so creates the default for this. I don't know whether this is DbNull or an actual value off the top of my head, but either way it will be an allowed value so won't throw an error.
As an aside you probably want to be setting the parameter to DbNull.Value
and not Nothing
:
If MyObject.MyTimestamp <> Nothing Then
cmd.Parameters.Item("@MyTimestamp").Value = MyObject.MyTimestamp
Else
cmd.Parameters.Item("@MyTimestamp").Value = DbNull.Value
End If
Upvotes: 3