上一张优化了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(五)的更多相关文章

  1. 一步步实现自己的ORM(二)

    在第一篇<一步步实现自己的ORM(一)>里,我们用反射获取类名.属性和值,我们用这些信息开发了简单的INSERT方法,在上一篇文章里我们提到主键为什么没有设置成自增长类型,单单从属性里我们 ...

  2. 一步步实现自己的ORM(一)

    最近在研究ORM,尝试着自己开发了一个简单的ORM.我个人不喜欢EF因为跟不上EF升级太快了,再说公司里还停留在c# 3.5时代,对于NHibernate配置太复杂看到就头晕,就心生自己做一个ORM的 ...

  3. 一步步实现自己的ORM(三)

    章节列表: <一步步实现自己的ORM(一)> <一步步实现自己的ORM(二)> 通过前面两篇文章,我们大致了解了ORM的基本原理,是通过Attribute+反射获取表的基本信息 ...

  4. 一步步实现自己的ORM(四)

    通过前3章文章,大致对ORM有一定的了解,但也存在效率低下(大量用了反射)和重复代码,今天我们要对ORM进行优化. 具体流程如下: 我们优化的第一个就是减少反射调用,我的思路是定义一个Mapping, ...

  5. day 67 django orm的基础

    django项目 安装: 创建项目 配置(setting,static,csrf) 创建app,python manage.py startapp app1 三部分 urls.py路由配置 1,普通正 ...

  6. [js高手之路] javascript面向对象写法与应用

    一.什么是对象? 对象是n个属性和方法组成的集合,如js内置的document, Date, Regexp, Math等等 document就是有很多的属性和方法, 如:getElementById, ...

  7. day 68 django 之api操作 | jQueryset集合与对象

    我们的orm里面分为: jQueryset集合, 还有对象, 我们的jqueryset集合里面可以有多个对象,这句话的意思就是我们的对象是最小的单位,不可以再拆分了,我们的jQueryset集合就相当 ...

  8. .Net Core + DDD基础分层 + 项目基本框架 + 个人总结

    为什么要写这篇文章 1,在大半年前,公司开发任务比较轻松,自己不知道干什么,但是又想要学习技术,比较迷茫,后面我接触到了博客园,看了一个帖子,深有感触,我当时不知道学习什么,于是我信息给他,他居然回复 ...

  9. 虚拟化--思杰citrix

    目前虚拟化主要有vmware,微软,思杰 一:从硬件搭建开始 硬件需要问的几个问题: a.负载均衡.防火墙.路由器怎么配置? b.新增一块存储的话,怎么新增? 二:安装citrix xen serve ...

随机推荐

  1. 【CQ18高一暑假前挑战赛5】标程

    [A:暴力] #include<bits/stdc++.h> using namespace std; ; int a[maxn],vis[maxn],N,M; int main() { ...

  2. BZOJ_4026_dC Loves Number Theory _主席树+欧拉函数

    BZOJ_4026_dC Loves Number Theory _主席树+欧拉函数 Description  dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯 竭 ...

  3. 洛谷 P1509 找啊找啊找GF(复习二维费用背包)

    传送门 题目背景 "找啊找啊找GF,找到一个好GF,吃顿饭啊拉拉手,你是我的好GF.再见." "诶,别再见啊..." 七夕...七夕...七夕这个日子,对于sq ...

  4. bzoj 2179 FFT快速傅立叶 —— FFT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2179 默写板子,注释的是忘记的地方. 代码如下: #include<iostream& ...

  5. 简单易用"里程碑"、"时间轴"<iOS小组件>

    非常感谢,帮助我的朋友们,谢谢你们.上次我的好朋友指出了我编码上(jwTextFiled工具组件)存在一些不规范问题,这次注意提高. 呆毛地址:https://github.com/NIUXINGJI ...

  6. Django - 导出项目依赖库到 requirements.txt

    两种方法: 虚拟环境: 使用 pip freeze pip freeze > requirements.txt # 这种方式推荐配合 virtualenv ,否则会把整个环境中的包都列出来. 只 ...

  7. yarn 基础

    创建: 2019/04/06  安装 mac brew install yarn  升级 brew upgrade yarn 确认是否成功 yarn --version  初始化项目 yarn ini ...

  8. E20181030-hm

    conquer  vt. 征服; 克服; 攻克; 打败(敌人);  vi. 得胜,胜利; recur vi. 复发; 重现; 再发生; 回想; recurrence n. 复回,重现; 反复,隐现; ...

  9. Codeforces Round #439 (Div. 2)C - The Intriguing Obsession(简单dp)

    传送门 题意 给出三个集合,每个集合的元素数量为a,b,c,现在需要连边,满足集合内元素不可达或最短路为3,求可行方案数 分析 设dp[i][j]为a集合元素为i个,b集合元素为j个的可行方案,易知( ...

  10. lightoj1064 【DP求方案】

    题意: n个相同的骰子,问你掷出>=x点数的可能性: 思路: dp[i][j]代表前 i 个骰子掷出 j 点数的方案数; 然后Σdp[n][x]-dp[n][6*n]就好了 卧槽,一开始想的是拆 ...