LayIM项目之基础数据获取代码优化,Dapper取代ADO.NET

前言

  最近在开发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> 方式来处理结果。我的代码如下:

 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,重构代码确实是有意思的事情,后续我会将各种体会做总结,如果能和读者产生共鸣那是最好不过的了。

时间: 2024-10-15 11:35:38

LayIM项目之基础数据获取代码优化,Dapper取代ADO.NET的相关文章

Asp.Net Core 项目搭建 基础配置 和MySql 的使用

一.开发环境准备 1.安装Visual Studio 2015,我这里安装的是专业版. 2.安装.NET Core SDK相关 需要安装  Visual Studio 2015 update3和NET Core 1.0.0 - VS 2015 Tooling 参考链接:http://www.cnblogs.com/fonour/p/5848933.html               http://www.cnblogs.com/linezero/p/NETCoreMySQL.html 解决方案

从零一起学Spring Boot之LayIM项目长成记(一) 初见 Spring Boot

项目背景 之前写过LayIM的.NET版后端实现,后来又写过一版Java的.当时用的是servlet,websocket和jdbc.虽然时间过去很久了,但是仍有些同学在关注.偶然间我听说了SpringBoot这么个东东,据说是省去了很多繁杂的配置.可以傻瓜式的创建项目,轻轻松松做出一个网站来,那么出于我对LayIM的情有独钟,于是乎想借用它来帮助我学习SpringBoot,并且全程记录,省的以后再走弯路和掌握解决问题的方法.(当然,我也是新手,我的解决方法就是百度,stackovreflow等网

Code::Blocks项目配置基础

File 菜单 New :新建( Empty file/file . class . project . build target ) . Recent projects/files :最近打开的项目 / 文件 . Import projects : Dev-C++ Project . VC6 dsw/dsp . VC8 vcproj/sln . Ctrl+Shift+S : Save all files . Save workspace (as) :将多个项目组织成一个工作空间,类似 VC 的

Karaf 依赖equinox and felix,karaf 本Apache的很多项目作为基础框架

6月17日是Apache Karaf作为Apache顶级项目.Karaf是个运行时包,包含了一个OSGi框架(Equinox或Felix).一个命令shell(Felix Gogo)及默认情况下内置的大量实用工具. 虽然Equinox与Felix可以单独使用,但Karaf旨在结合这两个框架出色的OSGi功能,并且保证其开箱即用.比如说,它包含了一个可配置的日志系统(基于Log4J,但针对众多通用的日志系统进行了包装).通过SSH实现的远程访问.通过ConfigAdmin(源代码位于etc目录中)

iOS项目开发基础

  iOS项目开发基础 前沿:整理了一个项目开发基础,涉及到开发初期的必备条件.源码请点击github地址下载. 目录 一.封装网络请求 二.json转model 三.方法顺序 四.文件结构 五.UITableView自动布局 六.UITableViewHeaderFooterView复用 七.计算label内容大小 一.封装网络请求 1.封装get请求 + (void)get:(NSString *)url param:(NSString *)param success:(void (^)(N

从零一起学Spring Boot之LayIM项目长成记(五)websocket

前言 距离上一篇已经比较久的时间了,项目也是开了个头.并且,由于网上的关于Spring Boot的websocket讲解也比较多.于是我采用了另外的一个通讯框架 t-io 来实现LayIM中的通讯功能.本篇会着重介绍我在研究与开发过程中踩过的坑和比较花费的时间的部分. WebSocket 在研究 t-io 的时候,我已经写过关于t-io框架的一些简单例子分析以及框架中关于 websocket 中的编解码代码分析等,有兴趣的同学可以先看一下.因为 在LayIM项目中我会是用到 Showcase D

【思库教育】2017PHP项目实战基础+进阶+项目之基础篇

下载链接: [思库教育]2017PHP项目实战基础+进阶+项目之基础篇 小白变大牛,您的专属资源库! 小白变大牛,您的专属资源库! 内容非常充实,可以看目录,设计的面多,项目多,技能多,如果掌握好,找一份PHP的工作,易如反掌!学完后可以到PHP小白变大牛精华区查找更加符合你的资源或者项目! [思库教育]2017PHP项目实战基础+进阶+项目之基础篇[思库教育]2017PHP项目实战基础+进阶+项目之进阶篇[思库教育]2017PHP项目实战基础+进阶+项目之项目篇小白变大牛!Python小白,J

项目开发基础概念

项目开发基础概念 企业的web项目类型 1. 商城 1.1 B2C 直销商城 商家与会员直接交易 ( Business To Customer ) 1.2 B2B 批发商城 商家与商家直接交易 1.3 B2B2C 购物平台 商家和会员在另一个商家提供的平台上面进行交易 1.4 C2B 定制商城 会员向商家发起定制商品的需求,商家去完成. 1.5 O2O 线上线下交易平台 1.6 C2C 二手交易平台 2. 门户网站[企业站和门户站] 3. 社交网络 4. 资讯论坛 5. 内部系统 6. 个人博客

Go推出的主要目的之一就是G内部大东西太多了,系统级开发巨型项目非常痛苦,Go定位取代C++,Go以简单取胜(KISS)

以前为了做compiler,研读+实现了几乎所有种类的语言.现在看语法手册几乎很快就可以理解整个语言的内容.后来我对比了一下go和rust,发现go的类型系统简直就是拼凑的.这会导致跟C语言一样,需要高超的技巧才能写大程序.而rust则没有这种问题,每个部分的组成都很和谐.---------------------------------------------------------------------- Rust是挺优秀的,函数式本来就比命令式来的优雅.但同时也要看到,两种语言的定位不同