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:
IHydratable
forces you to use select *
construct an all your queriesThe business case:
BgId
and BgShortDesc
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));
}
}
The fill method will throw an 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.
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;
}