升级到DNN 5.5.0后,我们必须在所有业务对象上实施IHydratable
。
这个想法似乎是一个很好的方式,但在玩IHydratable
后,我不再那么肯定了。
有两种可能性:
IHydratable
强制您使用select *
构建所有查询商业案例:
BgId
和BgShortDesc
BgId
和BgReportedUser
我的IHydratable
如下所示:
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方法将在上述任何一个sprocs上抛出IndexOutOfRangeException
,因为并非所有字段都返回IDataReader
。
解决问题的简单方法是在所有的sprocs中使用select *
,但这不是一个好习惯。
在这种情况下实施IHydratable
的正确方法是什么?
P.S。 请注意,我的示例过于简单,以便明白这一点。
答案 0 :(得分:1)
以下是建议:
public void Fill(IDataReader dr)
{
if (dr.ColumnExists("BgId"))
{
BgId = Convert.ToInt32(Null.SetNull(dr["BgId"], BgId));
}
//do the above for all the properties
}
修改强>
通过在SO(@JamesEggers和@Chad Grant)上的这2个答案的帮助下在IDataReader上编写扩展方法,找到了更好的方法。
/// <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;
}