[Spring.Net]RowMapper With Delegate
前言
之前在介紹Spring.Net的AdoTemplate時,通常會講到一個輕量級的OR mapping動作,叫做RowMapper。也就是透過一個class實作Spring.Data.Generic的IRowMapper<T>,來達到把Relational Data對應到object的property,並在mapping過程做相對應的處理。可以看一下之前文章中有介紹到:[Spring.Net]AdoTemplate回傳IList<T>
然而,通常這個class會將要return的object或IList<object>所有property都與datareader的欄位做binding,當遇到一張table有一兩百個欄位,但實際需求只要取一欄或兩欄時,這樣的mapping過程是相當耗時,會降低許多performance的。而為了這些動態的欄位需求,可能一欄、兩欄、不固定的欄位,難道都要新增對應的class去實作IRowMapper<T>嗎?還是就捨棄OR mapping的好處,改用DataTable回傳呢?
這邊要介紹個簡單的方法,其實就只是delegate,把RowMapper的動作改為Delegate一個匿名function,拋棄式的RowMapper。(可以用過一次就拋棄,或是用了多次再拋棄)。
(感謝J妹幫忙實作出來)
作法
先舉之前RowMapper的作法來當作比較,之前的RowMapper class長這樣:
public class ColumnSortRowMapper : IRowMapper<ColumnSort>
{
#region IRowMapper<ColumnSort> 成員
ColumnSort IRowMapper<ColumnSort>.MapRow(IDataReader reader, int rowNum)
{
ColumnSort columnSort = new ColumnSort();
columnSort.FunctionID = CovertType.DBToString(reader["FUN_ID"]);
columnSort.ColumnName = CovertType.DBToString(reader["COL_NAME"]);
columnSort.ColumnDescription = CovertType.DBToString(reader["COL_DESC"]);
columnSort.ColumnSEQ = Convert.ToInt16(reader["COL_SEQ"]);
columnSort.EntryID = CovertType.DBToString(reader["ENTRY_ID"]);
columnSort.EntryDate = CovertType.DBToString(reader["ENTRY_DATE"]);
columnSort.EntryTime = CovertType.DBToString(reader["ENTRY_TIME"]);
columnSort.ModifyID = CovertType.DBToString(reader["MODIFY_ID"]);
columnSort.ModifyDate = CovertType.DBToString(reader["MODIFY_DATE"]);
columnSort.ModifyTime = CovertType.DBToString(reader["MODIFY_TIME"]);
return columnSort;
}
#endregion
}
怎麼使用呢?
return AdoTemplate.QueryWithRowMapper<ColumnSort>(CommandType.Text, sql, new ColumnSortRowMapper(), objParameters);
透過這樣的用法,ColumnSortRowMapper就類似GridView的RowDataBound一樣,會根據撈到多少筆資料,就會assign多少個object到IList<ColumnSort>裡面。
假設我現在只要撈[FUN_ID]與[COL_NAME]兩欄呢?我們可以改寫成這樣:
return AdoTemplate.QueryWithRowMapperDelegate<ColumnSort>(CommandType.Text, sql, delegate(IDataReader dataReader, int rowNum)
{
ColumnSort columnSort = new ColumnSort();
columnSort.FunctionID = CovertType.DBToString(dataReader["FUN_ID"]);
columnSort.ColumnName = CovertType.DBToString(dataReader["COL_NAME"]);
return columnSort;
}
, objParameters);
只需要將原本QueryWithRowMapper<T>改成QueryWithRowMapperDelegate<T>,接著把原本放置RowMapper class的參數位置,改為delegate(IDataReder, int),在delegate的function中進行需要的mapping與處理即可。
如此一來就可以避免domain object property過多,在做ORM的時候performance太差的問題。
透過這樣也不需要每次都撈table的所有欄位,只要撈需要的欄位即可。
結論
要轉成用Lammda表示式搞不好也可以,不過沒啥太大差異啦。希望這個小技巧,可以幫助大家不用每次都return DataTable或是每次都mapping所有欄位。
參考
Spring.Net Document:http://www.springframework.net/docs/1.3.0/reference/html/ado.html
Document中的程式碼:
public virtual IList<Customer> GetCustomersWithDelegate()
{
return AdoTemplate.QueryWithRowMapperDelegate<Customer>(CommandType.Text, cmdText,
delegate(IDataReader dataReader, int rowNum)
{
Customer customer = new Customer();
customer.Address = dataReader.GetString(0);
customer.City = dataReader.GetString(1);
customer.CompanyName = dataReader.GetString(2);
customer.ContactName = dataReader.GetString(3);
customer.ContactTitle = dataReader.GetString(4);
customer.Country = dataReader.GetString(5);
customer.Fax = dataReader.GetString(6);
customer.Id = dataReader.GetString(7);
customer.Phone = dataReader.GetString(8);
customer.PostalCode = dataReader.GetString(9);
customer.Region = dataReader.GetString(10);
return customer;
});
}
blog 與課程更新內容,請前往新站位置:http://tdd.best/