c# - What are the best practices to parse data into objects in data access layer? -
i adding new features old asp.net application uses n-tier architecture. basic example can given as
object
public class test { public int id{get;set;} public int name{get;set;} }
data access layer
public static list<test> gettests() { list<test> list = new list<test>(); try { //codes sqldatareader dr = com.executereader(); while(dr.read()) list.add(filltestrecord(dr)) //codes } catch{} return list; } private static test filltestrecord(idatarecord dr) { test test = new test(); try{test.id = convert.toint32(dr["id"]);} catch{} try{test.name = convert.toint32(dr["name"]);} catch{} return test; }
the development requires me add new fields object classes , re-usability use 1 fill*record method each type of object. method can called many other dal methods idatarecord might not contain columns of object. hence put try-catch block every property separately. ensures available columns in idatarecord parsed properly.
my question is there better way of doing it? , best practices in type of architecture?
update
after reading comment/answer of david l , anup have tried way using extension method. method follows
public static bool trygetordinal(this idatarecord dr, string column, out int ordinal) { try { ordinal = dr.getordinal(column); } catch(exception ex) { ordinal = -1; //just setting value getordinal doesn't return return false; } return true; }
so filltestrecord
method be
private static test filltestrecord(idatarecord dr) { test test = new test(); int ordinal = default(int); if(dr.trygetordinal("id",out ordinal)) test.id = convert.toint32(dr.getvalue(ordinal)); if(dr.trygetordinal("name",out ordinal)) test.name = convert.tostring(dr.getvalue(ordinal)); return test; }
any suggestion on highly appreciated.
update 03-02-2016
during debugging found try-catch
takes big toll on performance if getordinal
throws error when supplied column name not found in datarecord
. wrote new method gets column names in datareader
, replaced getordinal
array.indexof
.
public static bool trygetordinal(this idatarecord dr, string[] columnnames, string column, out int ordinal) { ordinal = array.indexof(columnnames, column); return ordinal >= 0; }
and filltestrecord
becomes -
private static test filltestrecord(idatarecord dr, string[] columnnames) { test test = new test(); int ordinal = default(int); if(dr.trygetordinal(columnnames, "id",out ordinal)) test.id = convert.toint32(dr.getvalue(ordinal)); if(dr.trygetordinal(columnnames, "name",out ordinal)) test.name = convert.tostring(dr.getvalue(ordinal)); return test; }
column names passed fill method -
using (var dr = com.executereader()) { string[] colnames = dr.getcolumnnames(); while (dr.read()) list.add(filltestrecord(dr, colnames)); }
'getcolumnnames' new extension method -
public static string[] getcolumnnames(this idatareader dr) { string[] columnnames = new string[dr.fieldcount]; (int = 0; < dr.fieldcount; i++) { columnnames[i] = dr.getname(i).tolower(); } return columnnames; }
seems me in right direction.
long parsing being done in centralized location re-used upper level classes, looks solution.
the thing change replacing try-catch
statements checking if data exists in columns. surely there way tell (column not exist? db-null value?) implement using similar tryparse methods.
private static test filltestrecord(idatarecord dr) { test test = new test(); int tempid; if (tryparsedatarow<int>(dr, "id", out tempid)) { test.id = tempid; } return test; } private static bool tryparsedatarow<t>(idatarecord record, string column, out t value) { value = default(t); bool success = true; if (record == null) { //nothing can null object success = false; } else if (!record.hascolumn(column)) //not sure if throw exeption or return null. can check in project { success = false; } else if (record[column] != typeof(t)) { //object of unexpected type success = false; } else { //cast value output parameter value = (t)record[column]; } return success; }
and of course have implement hascolumn
method (implemented here extension):
/// <summary> /// determines whether specified record has column. /// </summary> /// <param name="record">the record.</param> /// <param name="columnname">name of column.</param> /// <returns>true if column exist, false otherwise</returns> public static bool hascolumn(this idatarecord record, string columnname) { (int = 0; < record.fieldcount; i++) { if (record.getname(i).equals(columnname, stringcomparison.invariantcultureignorecase)) return true; } return false; }
Comments
Post a Comment