77

At the moment, when I iterate over the DataRow instances, I do this.

foreach(DataRow row in table)
  return yield new Thingy { Name = row["hazaa"] };

Sooner of later (i.e. sooner), I'll get the table to be missing the column donkey and the poo will hit the fan. After some extensive googling (about 30 seconds) I discovered the following protection syntax.

foreach(DataRow row in table)
  if(row.Table.Columns.Contains("donkey"))
    return yield new Thingy { Name = row["hazaa"] };
  else
    return null;

Now - is this the simplest syntax?! Really? I was expecting a method that gets me the field if it exists or null otherwise. Or at least a Contains method directly on the row.

Am I missing something? I'll be mapping in many fields that way so the code will look dreadfully unreadable...

6 Answers 6

135

You can create an extension method to make it cleaner:

static class DataRowExtensions
{
    public static object GetValue(this DataRow row, string column)
    {
        return row.Table.Columns.Contains(column) ? row[column] : null;
    }
}

Now call it like below:

foreach(DataRow row in table)
    return yield new Thingy { Name = row.GetValue("hazaa") };
3
  • This was a nice solution. Not sure why it didn't get upvoted more. +1 from me anyway. Commented Aug 13, 2013 at 21:41
  • WoW! A Very neat solution. Thank you! Commented Aug 31, 2016 at 4:39
  • 1
    Nice one! However, implemented in the wild it should also check that row and column are ok values.
    – Erk
    Commented Oct 3, 2018 at 12:52
22

As your DataTable table always has the same columns ( they won`t change for any row ) you only need to check for the columnname once.

if (table.Columns.Contains("donkey"))
{
    foreach ...
}
3
  • This is nice for one column but however, as op said there will eventually be many columns so how will you manage them if you don't have an idea which may be present and which may not?
    – Varun K
    Commented Aug 13, 2013 at 12:00
  • @Varun, I for sure wouldn't keep the fixed string. What would you do if the column hazaa won`t exist anymore ?
    – Heslacher
    Commented Aug 13, 2013 at 12:15
  • @Heslacher That's the whole point. I need to manage that the column will sometimes come up and sometimes not. I have no control over that but I need to managed it still. Your example forks for a single column and can be extrapolated for multiple. However, please note that the question is if there's syntax for the check other than via table as you presented. Commented Aug 13, 2013 at 21:40
15

I really liked the approach taken by @Varun K. So, having that as a departing point I just wanted to put my two cents, in case it helps someone else. I simply improved it making it generic instead of just using object as a return type.

static class Extensions
{
  public static T Get<T>(this DataRow self, string column)
  {
    return self.Table.Columns.Contains(column)
      ? (T)self[column]
      : default(T);
    }
  }
}
3
  • Credit should be given where the credit is due. But your answer is so much of an improvement that I chose to re-accept it as the new correct answer. I also took the liberty of adapting it slightly to the generic nature of it by changing the names into more abstract ones. I hope it was okay. Commented Feb 19, 2021 at 13:54
  • Thanks for clarifying where credits should be. In addition, I appreciate a lot that you took the liberty to make the method even better. I believe that's the idea. To take ownership of the code and try to make each time one more step better. Commented Feb 19, 2021 at 16:58
  • 2
    This may lead to misleading results if, for example, you attempt to get an integer value from a column that doesn't exist. The method will return 0, which might lead someone to believe that the column existed and the field contained a valid value of 0.
    – vargonian
    Commented Mar 19, 2021 at 19:31
8

To build on the answer by Varun K, use a generic type parameter:

public static T GetValue<T>(this DataRow row, string column)
{
    if (!row.Table.Columns.Contains(column))
        return default(T);

    object value = row[ColumnName];
    if (value == DBNull.Value)
        return default(T);
    return (T)value;
}
4
foreach (DataColumn item in row.Table.Columns)
{
    switch (item.ColumnName)
    {
        case "ID":
            {
                p.ID = Convert.ToInt32(row[item.ColumnName].ToString());
            }
            break;
        case "firstName":
            {
                p.firstName = row[item.ColumnName].ToString();
            }
            break;
        case "lastName":
            {
                p.lastName = row[item.ColumnName].ToString();
            }
            break;

        default:
            break;
    };
}
1
  • This is actually perfect for what I need. (I don't love it, but I don't think I can do better...) Commented Aug 7, 2017 at 21:21
2

Sometimes a column name might exist, but a row does not contain the data for that column; for example, after filling DataTable using ReadXML.

A simple, fast and secure solution would be to use type checking:

if(row["columnname"].GetType() != typeof(System.DBNull)){
    //DataRow contains "columname"
}else{
    //a safe scope to set default cell data
}
1
  • 1
    I find it exciting that this question still gets new answers, upvotes and comments. Given that it's been shy of a week 7 whole years since it's been asked (and answered) I wonder how come users get it in their searches. Since it's been asked, EF took over and together with Dapper and nHybernate eliminated its relevance, I'd assume. How did you happen to stubble upon it? (Also, +1 for a new angle to it.) Commented Aug 9, 2020 at 7:45

Not the answer you're looking for? Browse other questions tagged or ask your own question.