標籤:採訪 對象 個數 思路 基礎 sed .text detail ati
前言
最近在開發LayIM融雲版,也在進行項目重構,現在在看之前的代碼,簡直不敢直視。不過不知道以後看現在的代碼是不是也是糟糕的一批。LayIM有個介面,一般接觸過的開發人員都不會生疏,就是init介面。介面返回的資料大概就是醬紫的:
1 { 2 "code": 0, 3 "msg": "", 4 "data": { 5 "mine": { 6 "username": "紙飛機", 7 "id": "100000", 8 "status": "online", 9 "sign": "在深邃的編碼世界,做一枚輕盈的紙飛機",10 "avatar": "/images/default.jpg"11 },12 "friend": [13 {14 "groupname": "前端碼屌",15 "id": 1,16 "online": 2,17 "list": [18 {19 "username": "賢心",20 "id": "100001",21 "avatar": "/images/default.jpg",22 "sign": "這些都是測試資料,實際使用請嚴格按照該格式返回"23 },24 {25 "username": "Z_子晴",26 "id": "108101",27 "avatar": "/images/default.jpg",28 "sign": "微電商達人"29 }30 ]31 },32 {33 "groupname": "網紅",34 "id": 2,35 "online": 3,36 "list": [37 {38 "username": "羅玉鳳",39 "id": "121286",40 "avatar": "/images/default.jpg",41 "sign": "在自己實力不濟的時候,不要去相信什麼媒體和記者。他們不是善良的人,有時候候他們的採訪對當事人而言就是陷阱"42 },43 {44 "username": "長澤梓Azusa",45 "id": "100001222",46 "sign": "我是日本女藝人長澤あずさ",47 "avatar": "/images/default.jpg"48 }49 ]50 }51 ],52 "group": [53 {54 "groupname": "前端群",55 "id": "101",56 "avatar": "/images/default.jpg"57 },58 {59 "groupname": "Fly社區官方群",60 "id": "102",61 "avatar": "/images/default.jpg"62 }63 ]64 }65 }LayIM init介面資料
總之,裡面嵌套了很多關係,比如,我的好友分組和好友的關係,還有其他的一些資料,其實,仔細分析一下,也就會各個擊破了。今天的重點不是這個資料,而是關於擷取這段資料代碼的重構。
之前的代碼
之前用的ADO.NET直接讀取的DataSet,然後進行資料處理,主要麻煩的是,還需要手動寫DataTable轉Model的過程,還要處理關係,比較繁瑣,並且需要知道其中的欄位。(當然,dapper也需要對應)。先看一下之前的代碼,總之這段代碼就是很古老的一種形式。
private BaseListResult ToBaseListResult(DataSet ds) { if (ds.Tables.Count > 0) { if (ds.Tables[0].Rows.Count ==0) { return new BaseListResult(); } //目前使用者的資訊 var rowMine = ds.Tables[0].Rows[0]; //使用者組資訊 var rowFriendDetails = ds.Tables[2].Rows.Cast<DataRow>().Select(x => new GroupUserEntity { id = x["uid"].ToInt(), avatar = x["avatar"].ToString(), groupid = x["gid"].ToInt(), remarkname = x["remarkname"].ToString(), username = x["nickname"].ToString(), sign = x["sign"].ToString(), //status之前的欄位是為空白的,現在我們把他的線上狀態加上,IsOnline方法接收一個userid參數,從Redis緩衝中讀取該使用者是否線上並返回 status = LayIMCache.Instance.IsOnline(x["uid"].ToInt()) ? "online" : "hide" }).OrderByDescending(x => x.status);//這裡要根據使用者是否線上這個欄位排序,保證線上使用者都在好友名單最上邊 //使用者組資訊,執行分組 var friend = ds.Tables[1].Rows.Cast<DataRow>().Select(x => new FriendGroupEntity { id = x["id"].ToInt(), groupname = x["name"].ToString(), online = 0, list = rowFriendDetails.Where(f => f.groupid == x["id"].ToInt()) }); //群組資訊 var group = ds.Tables[3].Rows.Cast<DataRow>().Select(x => new GroupEntity { id = x["id"].ToInt(), groupname = x["name"].ToString(), avatar = x["avatar"].ToString(), groupdesc = x["groupdesc"].ToString() }); //使用者皮膚,第一個是預設正在使用的 List<string> skin = ds.Tables[4].Rows.Cast<DataRow>().Select(x => x[0].ToString()).ToList(); BaseListResult result = new BaseListResult { mine = new UserEntity { id = rowMine["id"].ToInt(), avatar = rowMine["avatar"].ToString(), sign = rowMine["sign"].ToString(), username = rowMine["nickname"].ToString(), status = "online" }, friend = friend, group = group, skin = skin }; return result; } return null; }
下面,我們改用Dapper試試。重構過程先不談,看一下重構後的代碼處理:
public BaseListResult Handle(SqlMapper.GridReader reader) { var result = new BaseListResult(); //使用者本人資料 result.mine = reader.ReadFirst<UserEntity>(); //處理friend邏輯 start var friend = reader.Read<FriendGroupEntity>(); var groupUsers = reader.Read<GroupUserEntity>(); friend.ToList().ForEach(f => { //每一組的人分配給各個組 f.list = groupUsers?.Where(x => x.groupid == f.id); }); result.friend = friend; //處理friend邏輯 end //讀取使用者所在群 result.group = reader.Read<GroupEntity>(); return result; }
Dapper相較於ADO.NET比起來,就清爽多了,首先,處理GridReader,然後直接調用Read<T>方法,直接將表值轉換為Model,不過Model的值需要對應。然後轉換完之後,在進行一步邏輯處理,就是將相應的使用者跟好友分組的id對應上。最後一個返回,這樣看起來就清爽了許多,也不用處理的很麻煩。下文記錄一下我的開發思路。
代碼思路
首先要解決一個問題就是,解耦的問題,Dapper中有一個方法就是 QueryMultiple ,他是返回一個GridReader 對象,然後進行處理。那麼這個GridReader對象又必須在串連開著的時候使用,所以,不能直接返回然後關閉對象,所以,可以採用介面的形式,將處理方法提出去,或者,我剛才恰好想到的就是用Func<SqlMapper.GridReader,TResult> 方式來處理結果。My Code如下:
public static T QueryMultiple<T>(string sql, object param,CommandType commandType = CommandType.Text, IMultipleHandler<T> handler=null) { using (var connection = getConnection()) { using (var multi = connection.QueryMultiple(sql, param,commandType: commandType)) { if (handler == null) { return default(T); } return handler.Handle(multi); } } }
其中的IMultipleHandler 中就一個方法,Handle方法,參數為GridReader。然後返回 T類型的結果。所以上文中,我的調用方式很簡單了,就是傳入相應的處理類就可以了。
public class UserBaseListHandler : IMultipleHandler<BaseListResult>
其實我剛才突然想到,或許用Func更方便。不用再定義類繼承介面了。此篇,Over,重構代碼確實是有意思的事情,後續我會將各種體會做總結,如果能和讀者產生共鳴那是最好不過的了。
LayIM項目之基礎資料擷取代碼最佳化,Dapper取代ADO.NET