[ASP.NET] DataReader自動mapping到object

摘要:[ASP.NET] DataReader自動mapping到object

最近有點時間,整理紀錄一下平常用的一些小程式

因為蠻懶的所以如果在效能上不是很要求的物件,總是會用上一些小程式來處理,

像蠻喜歡把從DB叫出來的DataReader,用Reflection寫入物件中,

但有幾個前提要注意,

(1) 物件的property 的命名要和DataReader的Column Name 一樣,如果不一樣就只好自己做一個dictionary去mapping

(2) 物件的property請使用public,因為用private的話無法reflect 出來,也無法塞值進去

這是一個很簡單的例子,如果有錯請多包涵

先做一個簡單的Enity


public class IBECommonEntity
    {
        public int Idnum { get; set; }
        public EnableEnum Enable { get; set; }
        public StatusEnum Status { get; set; }
        public string Creater { get; set; }
        public DateTime CreateDate { get; set; }
        public string Modifier { get; set; }
        public DateTime? ModifyDate { get; set; }
    }

public class BEStatus : IBECommonEntity
    {
        public BEStatus(){}
        public string Name { get; set; }
        public string Test { get; set; }
        public StatusDataEnum StatusCategory { get; set; }
   }

然後我的Table結構如下

準備個簡單的Stored Procedure


CREATE PROCEDURE [dbo].[HR_GetStatusData_001]
	@StatusCategory int = NULL
AS
BEGIN

	SELECT * from [StatusData] with(nolock) where 
	(@StatusCategory is NULL or StatusCategory = @StatusCategory)
	and ([Status] = 0)
END

寫一個簡單的物件來呼叫DB


	public class DBSetting
    {
		//DBSource是一個自訂的Enum,主要是要讓我寫的其他程式取得我的DB Connection String(我只要點一下後面的字就出來了,原因還是懶)
		public static IDataReader GetDataReader(DBSource dbconstrID, string spID)
        {
			//這邊是我取得Connection String,程式就不寫了
            string cnstr = GetDBConnection(dbconstrID) ?? string.Empty;
			//這邊是我用Key值去取得我的SP Name
            string sp = GetSPValue(spID) ?? string.Empty;
            if (!string.IsNullOrEmpty(cnstr) && !string.IsNullOrEmpty(sp))
            {
			//簡單的寫一個取得DataReader方式,不傳Parameter了,相信很多人都非常厲害
                SqlConnection cn = new SqlConnection(cnstr);
                SqlCommand cmd = new SqlCommand(sp, cn);
                cmd.CommandType = CommandType.StoredProcedure;
                cn.Open();
                SqlDataReader dr = cmd.ExecuteReader(); 
                return dr;
            }
            return null;
        }
	}

 做一個Helper來處理把Dataredaer自動放入Object


	public class DBHelper
    {
		//用一個簡單的Reflection去把資料放入
		public static object DataReaderMapping(IDataReader dr, object obj)
        {
            PropertyInfo[] ps = obj.GetType().GetProperties();
            foreach (PropertyInfo p in ps)
            {
                p.SetValue(obj, ReturnValue(dr[p.Name]), null);
            }
            return obj;
        }
		
		//寫一個簡單的方式來過濾DataReader的資料
		private static object ReturnValue(object data)
        {
            string typename = data.GetType().Name.ToLower();
            if (typename.Contains("string"))
            {
                return data.ToString();
            }
            if (typename.Contains("int"))
            {
                return int.Parse(data.ToString());
            }
            if (typename.Contains("datetime"))
            {
                DateTime dateTimeValue = new DateTime();
                DateTime.TryParse(data.ToString(), out dateTimeValue);
                return dateTimeValue;
            }
            if (typename.Contains("decimal"))
            {
                return decimal.Parse(data.ToString());
            }
            return null;
        } 
	}

最後做一個Object來處理我的Enity,以後就可以不斷的呼叫Helper來幫忙


public class BOStatus
{	
	        public static IList getData() 
        {
            List statusList = new List();
            IDataReader dr = DBSetting.GetDataReader(DBSource.MainDBConstr, "GetStatusData");
            while (dr.Read())
            {
                 List drlist = new List();
                if (drlist.Count <= 0)
                {
                    drlist = DBHelper.DataReaderNameList(dr);
                }
                statusList.Add((BEStatus)DBHelper.DataReaderFilterMapping(dr, new BEStatus(), drlist));
            }
            return statusList;
        }
}

以上我們就可以很輕易的把DataReader放入我們的物件,不用再人工的一筆一筆寫,

最後一步,就是簡單的把它呈現在頁面


public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Message = "this is a test";
            IList list = BOStatus.getData();
            ViewBag.CountNum = list.Count;
            return View();
        }
	}

明眼人一看就知道我用MVC的範例,而且連改都懶得改 (慚愧)

以為這樣就結束了嗎? 當然還是有些問題,比較大的問題像是當我物件有增加新的property時,但DataReader沒有怎辦?

很簡單,系統就會拋異常,也就是給你錯誤畫面了,所以可以在DBHelper裡面做一個過濾去處理,這樣很簡單就處理掉了

END...