文章目錄
使用 Dapper 將 json string 轉換為 object
同事設計物件儲存在 DB 的 schema 時將非核心功能屬性 (e.g. 畫面顯示用或是狀態表示用) 轉為 json 放在單一欄位中而不是一一建立欄位。我覺得超酷的呀,雖然過去使用 PostgreSQL 時會刻意將非固定欄位的關連資料用 json type 儲放,但我從來沒想過可以極簡到把其他非核心的屬性都放至 json 中,同事真是強大呀
儘管在 DB 中可以是 json string 但對 application 依然是一般正常的 property,偶然間看到同事透過 JObject 手動 mapping,雖然高效但我還是擔心日後維護時可能會因為 fat finger 而出錯,於是就興起做些嘗試的想法,就來看看如何透過 Dapper 的 TypeHandler 來自動 mapping 吧
前提說明
將 User 非主要資訊(過去經驗)以 json 存至 Titles 中
application 使用物件時可直接取用
1. 調整 model
- 將原為 string 的 Titles 改用實際 class -
TitleModel
並改為 private 在原 class 中將 Titles property 一一列入並將 value 指向 Titles 內容
class User { public int Id { get; set; } public string Name { get; set; } public DateTime Birthday { get; set; } public string Addr { get; set; } private TitleModel Titles { get; set; } #region - 以下為 json string 中的屬性 - public string OrgName { get { return Titles.OrgName; } set { Titles.OrgName = value; } } public string Title { get { return Titles.Title; } set { Titles.Title = value; } } public string Award { get { return Titles.Award; } set { Titles.Award = value; } } public decimal Salary { get { return Titles.Salary; } set { Titles.Salary = value; } } #endregion } class TitleModel { public string OrgName { get; set; } public string Title { get; set; } public string Award { get; set; } public decimal Salary { get; set; } }
2. 客製 Dapper 的 TypeHandler
繼承
SqlMapper.ITypeHandler
並實作Parse
與SetValue
方法class UserTypeHandler : SqlMapper.ITypeHandler { //將 json string 從 db 取出時做轉型 public object Parse(Type destinationType, object value) { //將 DB 的 json string 內容轉為目標的型別 return JsonConvert.DeserializeObject(value.ToString(), destinationType); } //將值存回 db 時由 object 轉為 json public void SetValue(IDbDataParameter parameter, object value) { parameter.Value = (value == null) ? (object)DBNull.Value : JsonConvert.SerializeObject(value); parameter.DbType = DbType.String; } }
3. 方式使用
重點在於透過
SqlMapper.AddTypeHandler()
先行指定需要轉換的型別與對應使用的 TypeHandler//指定需要轉換的 Type 與對應使用的 TypeHandler SqlMapper.AddTypeHandler(typeof(TitleModel), new UserTypeHandler()); var users = new List<User>(); // db 連線 using (var conn = new SqlConnection("Data Source=.;database=YowkoTest;Integrated Security=SSPI;app=LINQPad")) { // dapper 取得資料 users = conn.Query<User>("SELECT * FROM dbo.[User]").ToList(); } // linqpad 輸出資料結果 users.Dump();
4. 實際產出
心得
以結果來看透過 Dapper 來轉換的方法與概念都滿簡單的,但過程中我也想過其他做法,最後決定的重點是較少的客製程式碼就可以降低出錯的機會。過了第一關接著下一步就得面臨同事們對執行效能上嚴苛的要求了,如果效能數據不好看我再來紀錄其他寫法XD
參考資料
文章作者 Yowko Tsai
上次更新 2021-11-03
授權合約
本部落格 (Yowko's Notes) 所有的文章內容(包含圖片),任何轉載行為,必須通知並獲本部落格作者 (Yowko Tsai) 的同意始得轉載,且轉載皆須註明出處與作者。
Yowko's Notes 由 Yowko Tsai 製作,以創用CC 姓名標示-非商業性-相同方式分享 3.0 台灣 授權條款 釋出。