一步步实现自己的ORM(五)
上一张优化了ORM的INSERT、UPDATE、DELETE,但将数据库里的值填充到实体类这块还没优化。另外有博友在网上咨询说你这个都是查询所有字段的,而他的需求是按需查询字段,不是一次性取出来所有字段的,在这里我请这位朋友耐心等待,这个会在后面章节提到的。这次我们先优化datareader->entity,将数据库里的值Mapping到实体类里,我们常用的有两种办法第一种是采用EMIT方式,第二种是采用Expression tree表达式,这两种方案在性能上差异不大,但写法上第二种较第一种比较容易,我在这里采用Expression tree表达式来完成实体类转换操作。
让我们先来看下Expression 表达式如何将DataReader转换成Object:
- IDataReader reader = null;
- Expression<Func<IDataReader, User>> expr = (r) => new User()
- {
- UserId = r.GetInt32(),
- CreatedTime = r.GetDateTime(),
- Email = r.GetString(),
- };
- var func = expr.Compile();
- func(reader);
在new User的时候采用对象初始化方式给属性赋值,而在实际项目中我们会遇到更复杂的,比如还要判断是否为DbNull,要不然转换会出错,在这里我定义一个GetValue<T>(int i)方法,专门做取值操作。
- class DbFieldReader
- {
- private IDataReader reader;
- public DbFieldReader(IDataReader reader)
- {
- this.reader = reader;
- }
- public T GetValue<T>(int index)
- {
- object value = reader.GetValue(index);
- if (value == DBNull.Value)
- return default(T);
- return (T)reader.GetValue(index);
- }
- }
现在将代码修改下,
- IDataReader reader = null;
- DbFieldReader fr = new DbFieldReader(reader);
- Expression<Func<DbFieldReader, User>> expr = (r) => new User()
- {
- UserId = r.GetValue<int>(),
- CreatedTime = r.GetValue<DateTime>(),
- Email = r.GetValue<string>(),
- };
- var func = expr.Compile();
- func(fr);
是不是简洁了很多?把判断代码转移到DbFieldReader类中处理,现在我们要将这个方法做成通用实体类转换,先分解下Expression表达式(如吐有错误,恳请大神指教)。
第一步定义参数,类型为DbFieldReader,参数名:r
- ParameterExpression parExpr = Expression.Parameter(typeof(DbFieldReader), "r");
第二步,调用User类的构造函数,代码如下:
- var newExpr = Expression.New(type.GetConstructors().First());
合并这2个表达式和运行结果:
- Expression<Func<DbFieldReader, User>> expr = (Expression<Func<DbFieldReader, User>>)Expression.Lambda(newExpr, parExpr);
基本的雏形出来了,现在要做的就是给属性赋值,怎么来呢?先来个简单的,就是给固定值。
- var userid = Expression.Bind(type.GetProperty("UserId"), Expression.Constant(, typeof(int)));
这就相当于UserId = 1的赋值操作,继续合并表达式:
- var type = typeof(User);
- ParameterExpression parExpr = Expression.Parameter(typeof(DbFieldReader), "r");
- var newExpr = Expression.New(type.GetConstructors().First());
- var userid = Expression.Bind(type.GetProperty("UserId"), Expression.Constant(, typeof(int)));
- var CreatedTime = Expression.Bind(type.GetProperty("CreatedTime"), Expression.Constant(DateTime.Now, typeof(DateTime)));
- var init = Expression.MemberInit(newExpr, userid, CreatedTime);
- Expression<Func<DbFieldReader, User>> expr = (Expression<Func<DbFieldReader, User>>)Expression.Lambda(init, parExpr);
常量赋值没问题后,下面就要来调用方法了。
- var method = typeof(DbFieldReader).GetMethods().Where(c => c.Name == "GetValue" && c.IsGenericMethod).First();
- var callExpr = Expression.Call(parExpr, method.MakeGenericMethod(typeof(int)), Expression.Constant());
var userid = Expression.Bind(type.GetProperty("UserId"), callExpr);
这句话相当于 r.GetValue<int>(0);
先获取GetValue方法,然后调用MakeGenericMethod生成泛型方法,Expression.Constant(0)就是参数值。
完整版代码:
- IDataReader reader = null;
- DbFieldReader fr = new DbFieldReader(reader);
- var entityMapping = AttributeMapping.Get<User>();
- ParameterExpression parExpr = Expression.Parameter(typeof(DbFieldReader), "r");
- var newExpr = Expression.New(entityMapping.EntityType.GetConstructors().First());
- var method = typeof(DbFieldReader).GetMethods().Where(c => c.Name == "GetValue" && c.IsGenericMethod).First();
- List<MemberBinding> memberBindings = new List<MemberBinding>();
- int index = ;
- foreach (var item in entityMapping.Members)
- {
- var callExpr = Expression.Call(parExpr, method.MakeGenericMethod(item.Member.PropertyType), Expression.Constant(index));
- var memberAssignment = Expression.Bind(item.Member, callExpr);
- memberBindings.Add(memberAssignment);
- index++;
- }
- var init = Expression.MemberInit(newExpr, memberBindings);
- Expression<Func<DbFieldReader, User>> expr = (Expression<Func<DbFieldReader, User>>)Expression.Lambda(init, parExpr);
当然我们还需要修改SQL语句,不能用SELECT * 语法,而是要用SELECT userid,email...from这样的语法
最终的代码代码下载:
http://files.cnblogs.com/files/sobaby/ORM05.zip
一步步实现自己的ORM(五)的更多相关文章
- 一步步实现自己的ORM(二)
在第一篇<一步步实现自己的ORM(一)>里,我们用反射获取类名.属性和值,我们用这些信息开发了简单的INSERT方法,在上一篇文章里我们提到主键为什么没有设置成自增长类型,单单从属性里我们 ...
- 一步步实现自己的ORM(一)
最近在研究ORM,尝试着自己开发了一个简单的ORM.我个人不喜欢EF因为跟不上EF升级太快了,再说公司里还停留在c# 3.5时代,对于NHibernate配置太复杂看到就头晕,就心生自己做一个ORM的 ...
- 一步步实现自己的ORM(三)
章节列表: <一步步实现自己的ORM(一)> <一步步实现自己的ORM(二)> 通过前面两篇文章,我们大致了解了ORM的基本原理,是通过Attribute+反射获取表的基本信息 ...
- 一步步实现自己的ORM(四)
通过前3章文章,大致对ORM有一定的了解,但也存在效率低下(大量用了反射)和重复代码,今天我们要对ORM进行优化. 具体流程如下: 我们优化的第一个就是减少反射调用,我的思路是定义一个Mapping, ...
- day 67 django orm的基础
django项目 安装: 创建项目 配置(setting,static,csrf) 创建app,python manage.py startapp app1 三部分 urls.py路由配置 1,普通正 ...
- [js高手之路] javascript面向对象写法与应用
一.什么是对象? 对象是n个属性和方法组成的集合,如js内置的document, Date, Regexp, Math等等 document就是有很多的属性和方法, 如:getElementById, ...
- day 68 django 之api操作 | jQueryset集合与对象
我们的orm里面分为: jQueryset集合, 还有对象, 我们的jqueryset集合里面可以有多个对象,这句话的意思就是我们的对象是最小的单位,不可以再拆分了,我们的jQueryset集合就相当 ...
- .Net Core + DDD基础分层 + 项目基本框架 + 个人总结
为什么要写这篇文章 1,在大半年前,公司开发任务比较轻松,自己不知道干什么,但是又想要学习技术,比较迷茫,后面我接触到了博客园,看了一个帖子,深有感触,我当时不知道学习什么,于是我信息给他,他居然回复 ...
- 虚拟化--思杰citrix
目前虚拟化主要有vmware,微软,思杰 一:从硬件搭建开始 硬件需要问的几个问题: a.负载均衡.防火墙.路由器怎么配置? b.新增一块存储的话,怎么新增? 二:安装citrix xen serve ...
随机推荐
- SSD Network Architecture--keras version
这里的网络架构和论文中插图中的网络架构是相一致的.对了,忘了说了,这里使用的keras版本是1.2.2,等源码读完之后,我自己改一个2.0.6版本上传到github上面.可别直接粘贴复制,里面有些中文 ...
- 003-更改pip的源让下载安装更加快捷
1 找到pip目录 C:\Python36\Lib\site-packages\pip\models 2 修改下面的index.py文件 将url设定为 https://pypi.douban.com ...
- HDU4825 Xor Sum(字典树解决最大异或问题)
Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整 ...
- poj3070 求斐波那契数列第n项 ——矩阵快速幂
题目:http://poj.org/problem?id=3070 用矩阵快速幂加速递推. 代码如下: #include<iostream> #include<cstdio> ...
- centos7 安装 python3.5
centos7 安装 python3.5 一. python虚拟环境virtualenv VirtualEnv用于在一台机器上创建多个独立的python运行环境,VirtualEnvWrapper为前 ...
- 关于try catch finally的执行顺序解释
偶然遇到了被问到finally的执行问题,忽然发现一直用的都是try catch 没有用过finally的情况,所以目前总结一下. 先抛出结论: 1.try内部正常执行try的内部逻辑,异常则执行ca ...
- 如何实现Vue已经弃用的$dispatch和$broadcast方法?
对于父子(含跨级)传递数据的通信方式,Vue.js 并没有提供原生的 API 来支持,而是推荐使用大型数据状态管理工具 Vuex,但 Vuex 对于小型项目来说用起来真的很麻烦. 在 Vue.js 1 ...
- 小白使用Web Deploy在vs2015中发布到iis遇到的问题及操作流程
整体流程详细参照:http://www.cnblogs.com/potential/p/3751426.html 问题1.未能连接到远程计算机,请确保在远程计算机上安装了 Web Deploy 并启动 ...
- HDU2852【树状数组+二分】
额..有点遗忘了树状数组特性了..印象中一直是前缀和,然后一定要记住树状数组是把给出的值(值太大可能可以离散化)也就是点到了区间,然后这个点存的值就是由自己来定了. 题意: 百度. 思路: 树状数组是 ...
- ZOJ3163【思维题】
每天取最远的那面 int main() { init(); int n,x,y; while(~scanf("%d%d%d",&n,&x,&y)) prin ...