Fun With Extension Methods - Extending IDataRecord Part 2

It's not uncommon that you have a method that accepts an object that implements the IDataRecord or IDataReader interface. It's also not uncommon that you cannot (fully) control the query that drives the IDataRecord. It could be the result of a SELECT * operation (bad idea) or it could be the results of a Stored Procedure for example. Especially in the latter case, it can be useful if you can check whether the IDataRecord contains a specific field. For example, you may want to check if the IDataRecord has a field called LastModified before you try to read and store this field in a local DateTime variable.

Unfortunately, the IDataRecord and IDataReader do not implement this behavior directly. However, it's easy to add with a simple extension method.

Extending IDataRecord

All the Get* methods on an IDataRecord instance throw an exception when you pass in a name or index that does not exist. For example, GetOrdinal (which returns the index of a field by its name) throws an IndexOutOfRangeException exception when you feed it a name that does not exist. Since throwing and catching exceptions is pretty slow, you shouldn't use this method to see if a field exists.

However, you can approach the problem from a different angle: the IDataRecord exposes a FieldCount property that returns the number of fields. Additionally, it has a GetName method that returns the name of a field by its index. When you combine these two members, you can loop through all the fields in the IDataRecord and compare the name of each field against the requested name. It would be pretty simply to create a simple helper method that would check the IDataRecord for a given field and return a boolean value indicating whether the field was found or not. Even better, with .NET 3.5 Extension Methods you can attach this behavior to an IDataRecord directly so you can use it exactly where you need it. Below you find a sample implementation of a FieldExists method that checks an IDataRecord for a given field:

using System;
using System.Data;

/// <summary>
/// The IDataRecordExtensions class provides extension methods to
/// objects implementing the IDataRecord interface.
/// </summary>
public static class IDataRecordExtensions
{
  /// <summary>
  /// Checks whether the given field name exists in the collection of fields.
  /// </summary>
  /// <param name="myRecord">The IDataRecord that is being extended.</param>
  /// <param name="fieldName">The name of the field that is being 
  /// searched for.</param>
  /// <returns><c>true</c> when the field exist in the IDataRecord fields collection; 
  /// <c>false</c> otherwise.</returns>
  public static bool FieldExists(this IDataRecord myRecord, string fieldName)
  {
    for (int i = 0; i < myRecord.FieldCount; i++)
    {
      string tempName = myRecord.GetName(i);
      if (fieldName == tempName)
      {
        return true;
      }
    }
    return false;
  }
}

Checking whether a field exists is now as simple as calling FieldExists:

bool idExists = someDataRecord.FieldExists("Id");

Carefully consider this code before using it in a very busy web site. It's currently not really optimized as it loops through each of the fields every time you want to check a field name. One way to optimize the use of this code is to never call it inside a loop. Instead, store the results of each search operation outside a loop and use that value inside the loop every time you need it. Additionally, you could store the collection of fields in a local variable so you don't have to loop through it every time.


Where to Next?

Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .


Consider making a donation
Please consider making a donation using PayPal. Your donation helps me to pay the bills so I can keep running Imar.Spaanjaars.Com, providing fresh content as often as possible.



Feedback by Other Visitors of Imar.Spaanjaars.Com

On Friday, February 26, 2010 10:37:00 AM ren said:
better:
for (int i = 0; i <= myRecord.FieldCount - 1; i++)
or
for (int i = 0; i < myRecord.FieldCount; i++)
On Saturday, February 27, 2010 10:09:45 AM Imar Spaanjaars said:
Hi ren,

You're absolutely right. A classical "off by one" mistake. I have no idea where that -1 comes from, and why I never noticed it before. That will teach me that I need to write more edge case unit tests ;-)

Thanks for bringing that to my attention. I have updated the article.

Cheers,

Imar

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the QuickDocId of the document.

For more information about the Talk Back feature, check out this news item.