17

What are the benefits of using the c# method DataRow.IsNull to determine a null value over checking if the row equals DbNull.value?

if(ds.Tables[0].Rows[0].IsNull("ROWNAME")) {do stuff}

vs

if(ds.Tables[0].Rows[0]["ROWNAME"] == DbNull.value) {do stuff}
Jarrod
  • 1,535
  • 3
  • 16
  • 19

4 Answers4

24

There is no real practical benefit. Use whichever one seems more readable to you.

As to the particular differences between them, the basic answer is that IsNull queries the null state for a particular record within a column. Using == DBNull.Value actually retrieves the value and does substitution in the case that it's actually null. In other words, IsNull checks the state without actually retrieving the value, and thus is slightly faster (in theory, at least).

It's theoretically possible for a column to return something other than DBNull.Value for a null value if you were to use a custom storage type, but this is never done (in my experience). If this were the case, IsNull would handle the case where the storage type used something other than DBNull.Value, but, again, I've never seen this done.

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
8

DBNull.Value != null

DBNull.Value stands for a column having the value <NULL>. Pop open a table and return some rows, see if any column in any row contains the <NULL>(ctrl 0) value. If you see one that is equivalent to DBNull.Value.

if you set a value to null or DBNull.Value then you will want to use IsNull(). That returns true if the value was set to either null or DBNull.Value.

Consider the following:

row["myCol"] = null;

row["myCol"] = DBNull.Value

if (row["myCol"] == DBNull.Value) //returns true

if (row["myCol"] == null) //returns false

if (row.IsNull("myCol")) //returns true

The point is if you are just checking for null or DBNull.Value use IsNull, if you are only checking for DBNull.Value explicitly say so and use that.

Kissaki
  • 8,810
  • 5
  • 40
  • 42
JonH
  • 32,732
  • 12
  • 87
  • 145
  • 1
    This is slightly misleading. When you set row["myCol"] = null it actually sets it to DBNull.Value. row.IsNull("myCol") and row("myCol") == DBNull.Value are actually equivalent. – Seth Reno Apr 08 '11 at 19:02
  • 1
    row["myCol"] = null; if (row["myCol"] == null) //returns false – Seth Reno Apr 08 '11 at 19:04
  • I'm not saying that DBNull.Value == null. I'm saying that inside of the DataRow class when you set it's value it converts null to DBNull.Value. – Seth Reno Apr 08 '11 at 19:08
  • @Seth Reno, so actually, on a DataRow, you would never need to check for null, because it will always be DBNull.Value? – Jarrod Apr 08 '11 at 19:25
  • @Jarrod - Yes. IMO this should not be marked as the correct answer. – Seth Reno Apr 08 '11 at 19:32
  • From what I can tell, setting row{"myCol"] = null is not even possible. It throws an error. But, checking for row["myCol"] == null is definitely false. – Jarrod Apr 08 '11 at 19:58
  • @Jarrod - setting row["mycol"] = null is definitely possible. I just did it. See my updated answer for a working example. – Seth Reno Apr 08 '11 at 20:19
  • @Seth Reno - You are confusing the readers. DBNull.Value != null, nor should it ever. – JonH Apr 08 '11 at 21:46
  • @JonH - I agree DBNull.Value != null. What I'm trying (and failing) to explain is that DataRow.IsNull() does not check for null only DBNull.Value. The value of the column in DataRow cannot be set to null because it automatically converts it to DBNull.Value. This means that your answer is inaccurate and misleading. Look at my answer for a running test that proves this. – Seth Reno Apr 08 '11 at 22:21
  • That is fine, IsNull again as I said checks for DBNull.Value and the INullable.null datatypes such as int?? or datetime?? – JonH Apr 11 '11 at 14:27
  • 1
    @Seth is correct here. The setter for `this[DataColumn]` on `DataRow` will not permit a genuine null reference to be assigned to the underlying storage array. If the column's data type is a value type, then it will throw an exception. Otherwise, it will assign `DBNull.Value`. `INullable` is used only when using one of the `SqlDataTypes`, not for ordinary types. – Adam Robinson Apr 11 '11 at 16:33
  • This is where DataRow replaces null with DBNull: https://referencesource.microsoft.com/#System.Data/fx/src/data/System/Data/DataRow.cs,306 I edited the answer text to fix the wrong implication. – Kissaki Oct 26 '21 at 12:11
  • I still don’t quite see what point this answer is trying to make though. It says to use IsNull over equality checks, but not why. – Kissaki Oct 26 '21 at 12:12
4

For one it's less typing. Other than that I think they are equivalent.

To try and clarify why I say they are equivalent.

[Test()]
public void test() {
    var t = new System.Data.DataTable();
    t.Columns.Add("col1");
    var r = t.NewRow();

        // null is converted to DBNull.Value by DataRow
        r["col1"] = null;
        Assert.IsFalse(r["col1"] == null);
        Assert.IsTrue(r["col1"] == DBNull.Value);
        Assert.IsTrue(r.IsNull("col1"));

        // nullable types w/o values are also converted
        int? val = null;
        Assert.IsFalse(val.HasValue);
        r["col1"] = val;
        Assert.IsTrue(r["col1"] == DBNull.Value);
        Assert.IsTrue(r.IsNull("col1"));


}
Seth Reno
  • 5,350
  • 4
  • 41
  • 44
  • Actually its not just typing. If I set a column to `null` and I check if it is equal to `DBNull.Value` then it returns false. If I were to use IsNull() method then whether I was checking for null or `DBNull.Value` the result returns true. In some cases you may want that. – JonH Apr 08 '11 at 18:45
  • Right but you did not mention that, you said it was just less typing. IsNull returns true if a value is either `null` or `DBNull.Value`. The two aren't equal. – JonH Apr 08 '11 at 18:49
  • @JonH - This is because when you set the value in the data row to null it actually sets it to DBNull.Value. – Seth Reno Apr 08 '11 at 18:59
  • 1
    @Seth Reno - no no no `DBNull.Value != null`. – JonH Apr 08 '11 at 19:00
  • @JohnH - I know that. You misunderstand what I'm saying. – Seth Reno Apr 08 '11 at 19:03
  • @Seth Reno-I understand that what I am trying to persuade the OP and others is that whether something is null or DBNull.Value then you'll want to use IsNull. The op asked what are the performance differences, this is not about performance, this is about accuracy. See this for more http://blogs.msdn.com/b/aconrad/archive/2005/02/28/381859.aspx. – JonH Apr 09 '11 at 15:21
  • @JohnH - I don't think you do understand. The value of a column in a DataRow can never be null. You can try and set it to null but it will get converted to DBNull.Value during the set. DataRow.IsNull does not check for null because that can never happen. – Seth Reno Apr 09 '11 at 18:58
  • @JohnH - That link was actually one of the reasons I posted this question, because it totally confused me. I mean, what does "True - but bad news" mean when he is talking about DBNull.Value? He never convincingly explains what the "bad news" is. Also, doesn't this link show that @Seth Reno is right in what he is saying. The author even states that "_internally the DataSet translates the null value to be DBNull.Value_". What is the point of Row.IsNull if the value is always going to be DBNull.Value. – Jarrod Apr 11 '11 at 14:09
  • @Jarrod - I think this relates to some of the issues encountered back when the nullable types were being implemented. I agree that DBNull.Value is the conversion that takes place for this specific example. My point was to explain that DBNull.Value does not equal null. For instance, assume your type was a nullable int assigned to null. I misinterpreted Jarrod, because in the beginning his post only read somethign to the effect of `asside from the amount of text entered there is no difference` and then the post was changed. I agree with the above code, that wasn't the initial question. – JonH Apr 11 '11 at 14:14
  • Ran out of characters, the thing to remember is that IsNull returns true for DBNull.Value and INullable data types. So if you ever have to deal with the nullable types such as int??, or datetime?? dbnull.value doesn't do a check for those types. Hence the IsNull function. – JonH Apr 11 '11 at 14:25
  • @JohnH - Your last statement is completely false. Nullable types are also converted to DBNull.Value by DataRow. – Seth Reno Apr 11 '11 at 14:41
  • @Seth Reno - That was news to me. The post asked about performance, the answer is there is no performance difference. What is the new point of `IsNull()` then ? – JonH Apr 11 '11 at 14:47
  • @JohnH - ??? - The post does not mention performance. The question is what's the difference between DataRow.IsNull() and DataRow["col"] == DBNull.Value. IsNull is a function defined by the DataRow class. – Seth Reno Apr 11 '11 at 14:52
  • @Seth Reno - So again the question is what purpose does `IsNull()` serve being that `you` mentioned the conversions take place for nullable types as well. – JonH Apr 11 '11 at 15:01
  • @JohnH - Like my answer says: "For one it's less typing. Other than that I think they are equivalent.". – Seth Reno Apr 11 '11 at 15:13
  • @Seth Reno - In most cases MS would deprecate it if that was the reason. – JonH Apr 11 '11 at 15:28
  • 3
    They are functionally equivalent, but `IsNull` is faster, as it checks the underlying storage layer's null bit for that record rather than actually retrieving the value. – Adam Robinson Apr 11 '11 at 16:37
  • @Adam Robinson - I think that should be the accepted answer. You should post it. – Seth Reno Apr 11 '11 at 16:53
0

FWIW, I wrote a bunch of DataRow extension methods — CastAsXXX() — to avoid having to deal with DB nullability...or at least defer it a bit B^). Here's my CastAsInt() and CastAsIntNullable() methods:

#region downcast to int

public static int CastAsInt( this DataRow row , int index )
{
  return toInt( row[index] ) ;
}
public static int CastAsInt( this DataRow row , string columnName )
{
  return toInt( row[columnName] ) ;
}

public static int? CastAsIntNullable( this DataRow row , int index )
{
  return toIntNullable( row[index] );
}
public static int? CastAsIntNullable( this DataRow row , string columnName )
{
  return toIntNullable( row[columnName] ) ;
}

#region conversion helpers

private static int toInt( object o )
{
  int value = (int)o;
  return value;
}

private static int? toIntNullable( object o )
{
  bool hasValue = !( o is DBNull );
  int? value    = ( hasValue ? (int?) o : (int?) null ) ;
  return value;
}

#endregion conversion helpers

#endregion downcast to int

Usage is pretty straightforward. You just need to state your expectations up front.

DataRow dr = GetADataRowFromSomewhere() ;
// Throws NullReferenceException if the column is null
int     x  = dr.CastAsInt(         "column_1" ) ;
// Is perfectly happy with nulls (as it should be)
int?    y  = dr.CastAsIntNullable( "column_1" ) ;

I tried to make them generic, but no dice unless I'm willing to correlate NULLs from the database with the default value for the type (e.g., 0 for numeric types), which I'm not.

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135
  • 2
    How are these different from Field in [System.Data.RowExtendsions](http://msdn.microsoft.com/en-us/library/system.data.datarowextensions.aspx)? – Jacek Sieka Jun 05 '12 at 12:10