Question

I have two cases to extract information from the IDataReader object

Case - 1 - Length, calculates ordinal and then parse string

public static string GetString(IDataReader rdr, string columnName)
{
    int ordinal = rdr.GetOrdinal(columnName);
    if (rdr.IsDBNull(ordinal))
    {
        return string.Empty;
    }
    return (string)rdr[ordinal];
}

Case - 2, short way, getting data without calculating ordinal

public static string GetString(IDataReader rdr, string columnName)
{
    return (string)rdr[columnName];
}

Which technique should be preferred and why and if any specific context ?

Was it helpful?

Solution

SqlDataReader's this[string name] looks like:

public override object this[string name]
{
    get
    {
        return this.GetValue(this.GetOrdinal(name));
    }
}

so it calculates ordinal internaly, and there is no difference what way to use.

UPDATE

Yo can rewrite your code as:

public static string GetString(IDataReader rdr, string columnName)
{
    return (rdr[columnName] as String)??String.Empty;
}

OTHER TIPS

Here's what MSIL looks like for your first method:

.method public hidebysig static string  GetString(class [System.Data]System.Data.IDataReader rdr,
                                                  string columnName) cil managed
{
  // Code size       49 (0x31)
  .maxstack  2
  .locals init ([0] int32 ordinal,
           [1] string CS$1$0000,
           [2] bool CS$4$0001)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  callvirt   instance int32 [System.Data]System.Data.IDataRecord::GetOrdinal(string)
  IL_0008:  stloc.0
  IL_0009:  ldarg.0
  IL_000a:  ldloc.0
  IL_000b:  callvirt   instance bool [System.Data]System.Data.IDataRecord::IsDBNull(int32)
  IL_0010:  ldc.i4.0
  IL_0011:  ceq
  IL_0013:  stloc.2
  IL_0014:  ldloc.2
  IL_0015:  brtrue.s   IL_0020
  IL_0017:  nop
  IL_0018:  ldsfld     string [mscorlib]System.String::Empty
  IL_001d:  stloc.1
  IL_001e:  br.s       IL_002f
  IL_0020:  ldarg.0
  IL_0021:  ldloc.0
  IL_0022:  callvirt   instance object [System.Data]System.Data.IDataRecord::get_Item(int32)
  IL_0027:  castclass  [mscorlib]System.String
  IL_002c:  stloc.1
  IL_002d:  br.s       IL_002f
  IL_002f:  ldloc.1
  IL_0030:  ret
} // end of method Program::GetString

And for your second method:

.method public hidebysig static string  GetStringShort(class [System.Data]System.Data.IDataReader rdr,
                                                       string columnName) cil managed
{
  // Code size       18 (0x12)
  .maxstack  2
  .locals init ([0] string CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  callvirt   instance object [System.Data]System.Data.IDataRecord::get_Item(string)
  IL_0008:  castclass  [mscorlib]System.String
  IL_000d:  stloc.0
  IL_000e:  br.s       IL_0010
  IL_0010:  ldloc.0
  IL_0011:  ret
} // end of method Program::GetStringShort

So the methods are definitely not the same. As to which is better, you don't say why you want to calculate the ordinal so it's hard to say which is better for your situation.

I don't think there's really a difference (they do the same thing), the second seems more readable to me as the introduction of the 'index' is confusing for those who don't know how the reader is working. Hide needless complexity I say. You should go a step further and make it a generic you can use anywhere, like this:

    private static T FromDbValue<T>(IDataReader rdr, string columnName)
    {
        var value = rdr[columnName];

        if (value == DBNull.Value)
        {
            return default(T);
        }

        return (T)value;
    }

Invoking it is easy:

var someString = FromDbValue<string>(rdr, "CustomerName");

Edit: You're not checking for DBNull in your second example, so the cast would fail on nulls. However, generally speaking the two approaches are the same.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top