views:

37

answers:

1

After upgrading to DNN 5.5.0 we had to implement IHydratable on all of our business objects.

This idea seemed like a good way to go at first, but after playing with IHydratable I'm not so sure any more.

There are two possibilities:

  1. I'm doing it wrong
  2. IHydratable forces you to use select * construct an all your queries

The business case:

My first sproc returns the BgId and BgShortDesc

My second sproc returns BgId and BgReportedUser

My IHydratable is implemented as show below:

public class Bug : IHydratable
    {

            public int BgId {get;set;}
            public string BgShortDesc {get;set;}
            public int BgReportedUser {get;set;}
            public DateTime BgReportedDate {get;set;}

            public Bug(){}

        public int KeyID
        {
            get { return BgId; }
            set { BgId = value; }
        }

        public void Fill(IDataReader dr)
        {
                BgId = Convert.ToInt32(Null.SetNull(dr["BgId"], BgId));

                BgShortDesc = Convert.ToString(Null.SetNull(dr["BgShortDesc"], BgShortDesc));
                BgReportedUser = Convert.ToInt32(Null.SetNull(dr["BgReportedUser"], BgReportedUser));
                BgReportedDate = Convert.ToDateTime(Null.SetNull(dr["BgReportedDate"], BgReportedDate));

        }
}

Fill method will throw IndexOutOfRangeException on any of the above sprocs, since not all the fields get returned with IDataReader.

The easy way around the problem is to use select * in all of the sprocs, but that's not a good practice.

What's the PROPER way of implementing IHydratable in this scenario?

p.s. keep in mind that my example is oversimplified to get the point across.

A: 

I got a feasible answer to this on another forum

Here's the suggestion:

    public void Fill(IDataReader dr)
    {
            if (dr.ColumnExists("BgId"))
            {
              BgId = Convert.ToInt32(Null.SetNull(dr["BgId"], BgId));
            }
            //do the above for all the properties
    }

EDIT:

Found a better way of doing this by writing an extension method on IDataReader with the help of these 2 answers on SO (@JamesEggers and @Chad Grant)

    /// <summary>
    /// Check if the column exists in the datareader before accessing its value
    /// </summary>
    /// <param name="reader">DataReader</param>
    /// <param name="columnName">Column name</param>
    /// <returns>True if column exists, false if not</returns>
    public static bool ColumnExists(this IDataReader reader, string columnName)
    {
        for (int i = 0; i < reader.FieldCount; i++)
        {
            if (reader.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
            {
                return true;
            }
        }

        return false;
    }
roman m