DataReader Helper Part 2
בהמשך ל
פוסט הקודם שכתבתי על איך להביא נתונים מטבלה שממופה לאוביקט (אחד לאחד - עבור כל עמודה יש מאפיין עם אותו שם).
אז כמו שכתב
רותם, ברגע שזה לא בדיוק אחד לאחד, זה לא יעבוד.
אז הנה הגירסא המורחבת של הפיתרון, (אפשר להוריד אותו
מכאן.) (אולי כדאי להעלות אותו גם ל Code Plex, מה אתם אומרים ?)
וכמובן על ידי attribute,
ואם כבר הרחבתי את הפיתרון, אז שיניתי את המתודה ל Extension.
הנה הקוד של ה attribute:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class MapAttribute : Attribute
{
public string DatabaseColumn { get; set; }
public bool UseMap { get; set; }
public MapAttribute()
{
UseMap = true;
}
}
יש לנו שני מאפיינים,
הראשון מחזיק את שם העמודה ב DB,
השני אומר האם להשתמש בעמודה הזאת (כי יתכן שיש לנו מאפיינים שהערך לא מגיע מה DB)
כך נראה האובייקט שלי:
public class Courses
{
public int Id { get; set; }
public string Name { get; set; }
[Map(DatabaseColumn = "You")]
public bool? IsActive { get; set; }
[Map(UseMap = false)]
public double Age { get; set; }
}
לא חייבים להשתמש ב attribute,
במידה ואנחנו לא רוצים שעמודה מסויימת תמופה, או שאנחנו רוצים למפות עם שם אחר
נוכל להשתמש עם ה attribute.
והנה הקוד המעודכן של המתודה: (שימו לב זה הפך ל Extension)
public static object Build(this DbDataReader reader, Type type)
{
ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes);
if (ctor == null)
{
throw new Exception(@"To use reader helper,
your class must have a
parameterless constructor");
}
object newObject = ctor.Invoke(null);
PropertyInfo[] properties = type.GetProperties();
foreach (var prop in properties)
{
string readerPropName = prop.Name;
object[] maps = prop.GetCustomAttributes(typeof(MapAttribute), false);
if (maps.Length == 1)
{
MapAttribute map = (MapAttribute)maps[0];
if (!map.UseMap)
{
continue;
}
if (!string.IsNullOrEmpty(map.DatabaseColumn))
{
readerPropName = map.DatabaseColumn;
}
}
object value = reader[readerPropName];
if (value is DBNull)
{
prop.SetValue(newObject, null, null);
}
else
{
prop.SetValue(newObject, value, null);
}
}
return newObject;
}
וההסבר:
נקבל את ה ctro,
נבדוק שיש אחד כזה ללא פרמטרים.
נייצר מופע שלו.
ונרוץ בלולאה על כל המאפיינים, עד כאן כמו בגירסה הקודמת.
נבדוק האם יש attribute מסוג MapAttribute
במידה וכן, והמאפיין UseMap הוגדר כ false, נתעלם מהמאפיין הזה
במידה ויש ערך במאפיין DatabaseColumn, נקח את ערכו.
וכעת זה ממשיך כמו בגירסה הקודמת, לוקח את הערך ומשים אותו בתוך המאפיין.
וכך נראה הקוד שמשתמש בו:
while (reader.Read())
{
reqs.Add((Courses)reader.Build(typeof(Courses)));
}