views:

140

answers:

3

When working with namespaces such as System.Data.Odbc or System.Data.OracleClient the various data reader methods generally require an integer corresponding to a column be provided to the functions (e.g. OracleDataReader.GetInt32).

My question is this, what is the best way to work with these functions so that the code is fairly self-documenting. Right now, it seems to me that there are three options, namely:

// Option One - Just provide the integer value
string myString = oraData.GetString[0];

// Option Two - Provide the integer value using a constant
string myString = oraData.GetString[FIELD_NAME];

// Option Three - Provide the column name and use System.Convert to return the correct value
string myString = Convert.ToString(oraData["Field_Name"]);

Each of these techniques seem to have there own pros and cons and I'm curious to see what others think, or if there is a better way to do it.

+1  A: 

I typically use option 3. I like it because if the underlying query ever changes the column order it will still work, and it shows the name of what you're asking for right there rather than some magic number.

However, I use a lot of VB.Net, so the Convert.ToString() part can be done implicitly. C# types may have a different preference.

Also, there is a very small penalty for using field name rather than a column ordinal. I normally feel it's justified, but depending on your app you might want to take that into account.

Joel Coehoorn
+2  A: 

I have always done it this way:

int columnIndex = dataReader.GetOrdinal("field");

if (!dataReader.IsDBNull(columnIndex))
    String myString = dataReader.GetString(columnIndex);

The idea being that GetOrdinal will fail with an IndexOutOfRangeException when I try to get a field that is not in the reader. I want this exception because it tells me quickly that there is a mismatch between my code and my DB.

Also GetOrdinal is much less brittle than hardcoding the ordinal itself as a magic number.

Andrew Hare
+1  A: 

I agree with Andrew Hare, with the addition that I've enclosed the functionality in an overloaded extension method that simplifies the operation:

public static string GetStringByName(this OracleDataReader reader, 
                                     string columnName, 
                                     string defaultValue)
{
   string result = defaultValue;
   int columnIndex = reader.GetOrdinal(columnName);
   if(!reader.IsDbNull(columnName)
   {
      result = (string) reader.GetString(columnIndex);
   }
   return result;
}

Anyway, just a refactoring that helped me tremendously.

Mike Hofer