一步步实现自己的ORM(三)
章节列表:
通过前面两篇文章,我们大致了解了ORM的基本原理,是通过Attribute+反射获取表的基本信息,再用表名和字段名拼接成SQL语句。而前面我们只是完成了CRUD部分的CUD,还没完成读取(Retrieve)操作,今天就来完成这个R操作。我们先看下平时写实体类转换代码是怎么写的:
static List<User> ToObject1()
{
SqlDataReader reader = null;
List<User> list = new List<User>();
while (reader.Read())
{
User user = new User();
if (reader["UserId"] != null)
user.UserId = (int)reader["UserId"]; if (reader["Email"] != null)
user.Email = (string)reader["Email"]; if (reader["CreatedTime"] != null)
user.CreatedTime = (DateTime)reader["CreatedTime"]; list.Add(user);
}
return list;
}
经常写DataReader对象转换成实体类的童鞋们,WHILE循环里的内容是根据实体类的不同代码而有所不同,循环外的代码则是固定不变的,现在我们要把变化的代码抽离出来,我们还是请出明星--反射。
在前面章节我们都是用反射读取实体类里的,比如typeof(User).GetProperty("UserId").GetValue(obj,null),有GetValue肯定也有SetValue,我们看下SetValue的定义:
public virtual void SetValue(
Object obj,
Object value,
Object[] index
)
obj:将设置其属性值的对象。
value:新的属性值。
index : 索引化属性的可选索引值。 对于非索引化属性,该值应为 null。
示例代码:
User user = new User();
typeof(User).GetProperty("UserId").SetValue(user, , null);
Console.WriteLine(user.UserId);
输出结果我就不贴图了,是“10”。
HOHO,我们开始构建代码,步骤如下:
1. new 实体类对象
2. 反射类的属性,然后用SetValue给实体类属性赋值
具体代码如下:
string sql = "select * from tb_users";
SqlConnection conn = new SqlConnection(EntityHelper.connectionString);
conn.Open(); var cmd = conn.CreateCommand();
cmd.CommandText = sql; SqlDataReader reader = cmd.ExecuteReader();
List<User> list = new List<User>();
var type = typeof(User);
var properties = type.GetProperties();
while (reader.Read())
{
User user = new User();
for (int i = ; i < properties.Length; i++)
{
var pi = properties[i];
if (reader[pi.Name] != null) //等同于 if (reader["UserId"] != null)这样的语句
pi.SetValue(user, reader[pi.Name], null); //等同于 user.UserId = (int)reader["UserId"];
} list.Add(user);
} foreach (var item in list)
{
Console.WriteLine("UserId:{0},Email:{1},CreatedTime:{2}", item.UserId, item.Email, item.CreatedTime);
}
运行结果:

下面一个问题来了,我们看这一行代码
User user = new User();
难道我们每次都要这么写这样的代码吗,能不能做一个通用的吗?这需要我们用反射实例化一个类,我们请Activator.CreateInstance帮忙创建实例,代码如下:
var type = typeof(User);
var user = Activator.CreateInstance(type);
创建实例和给属性赋值都动态完成,我稍稍修改下代码,只要传递SQL语句就可以返回集合。
static List<T> GetEntityList<T>(string sql)
{
SqlConnection conn = new SqlConnection(EntityHelper.connectionString);
conn.Open(); var cmd = conn.CreateCommand();
cmd.CommandText = sql; SqlDataReader reader = cmd.ExecuteReader();
List<T> list = new List<T>();
var type = typeof(T);
var properties = type.GetProperties();
while (reader.Read())
{
var user = Activator.CreateInstance(type);
for (int i = ; i < properties.Length; i++)
{
var pi = properties[i];
if (reader[pi.Name] != null) //等同于 if (reader["UserId"] != null)这样的语句
pi.SetValue(user, reader[pi.Name], null); //等同于 user.UserId = (int)reader["UserId"];
} list.Add((T)user);
}
return list;
}
最后我们在增加如下方法:
Get(object[] values) 根据主键获取实体类
GetList<T>(string where,string orderBy) 按条件查询实体类
public static T Get<T>(object[] values)
{
var type = typeof(T);
Dictionary<string, object> parameters = new Dictionary<string, object>();
var properties = type.GetProperties(); string tableName = string.Empty;
TableAttribute[] tableAttrs = (TableAttribute[])type.GetCustomAttributes(typeof(TableAttribute), true);
if (tableAttrs.Length > )
{
tableName = tableAttrs[].Name;
}
else
{
tableName = type.Name;
} /*将所有的列放到集合里*/
List<IdAttribute> columns = new List<IdAttribute>();
for (int i = ; i < properties.Length; i++)
{
var pi = properties[i];
var attrs = (IdAttribute[])pi.GetCustomAttributes(typeof(IdAttribute), true);
if (attrs.Length > )
{
columns.Add(attrs[]);
}
}
if (columns.Count != values.Length)
throw new ArgumentException("参数个数和主键数不一致"); StringBuilder sql = new StringBuilder();
sql.Append("SELECT * FROM [").Append(tableName).Append("] ").Append(" WHERE "); for (int i = ; i < columns.Count; i++)
{
if (i > ) //考虑到有多个主键
sql.Append(" AND "); sql.Append(columns[i].Name).Append("=").Append("@p").Append(i); /*参数*/
parameters.Add("@p" + i, values[i]);
}
Console.WriteLine(sql);
return GetEntityList<T>(sql.ToString(), parameters).FirstOrDefault();
}
public static List<T> GetList<T>(string where,string orderBy)
{
var type = typeof(T);
Dictionary<string, object> parameters = new Dictionary<string, object>();
var properties = type.GetProperties(); string tableName = string.Empty;
TableAttribute[] tableAttrs = (TableAttribute[])type.GetCustomAttributes(typeof(TableAttribute), true);
if (tableAttrs.Length > )
{
tableName = tableAttrs[].Name;
}
else
{
tableName = type.Name;
} StringBuilder sql = new StringBuilder();
sql.Append("SELECT * FROM [").Append(tableName).Append("] ");
if (string.IsNullOrEmpty(where))
sql.Append(" WHERE ").Append(where); if (string.IsNullOrEmpty(orderBy))
sql.Append(" Order By ").Append(orderBy); Console.WriteLine(sql);
return GetEntityList<T>(sql.ToString(), parameters);
} public static List<T> GetEntityList<T>(string sql, Dictionary<string, object> parameters)
{
SqlConnection conn = new SqlConnection(EntityHelper.connectionString);
conn.Open(); var cmd = conn.CreateCommand();
cmd.CommandText = sql;
if (parameters != null && parameters.Count > )
{
foreach (var item in parameters)
{
var pa = cmd.CreateParameter();
pa.ParameterName = item.Key;
pa.Value = item.Value ?? DBNull.Value;
cmd.Parameters.Add(pa);
}
} SqlDataReader reader = cmd.ExecuteReader();
List<T> list = new List<T>();
var type = typeof(T);
var properties = type.GetProperties();
while (reader.Read())
{
var user = Activator.CreateInstance(type);
for (int i = ; i < properties.Length; i++)
{
var pi = properties[i];
if (reader[pi.Name] != null) //等同于 if (reader["UserId"] != null)这样的语句
pi.SetValue(user, reader[pi.Name], null); //等同于 user.UserId = (int)reader["UserId"];
} list.Add((T)user);
}
return list;
}
下载代码:http://files.cnblogs.com/files/sobaby/ORM03.zip
EntityHelper里重复代码很多,而且采用反射效率很低,下一章就开始优化代码。
一步步实现自己的ORM(三)的更多相关文章
- 一步步实现自己的ORM(二)
在第一篇<一步步实现自己的ORM(一)>里,我们用反射获取类名.属性和值,我们用这些信息开发了简单的INSERT方法,在上一篇文章里我们提到主键为什么没有设置成自增长类型,单单从属性里我们 ...
- 一步步实现自己的ORM(一)
最近在研究ORM,尝试着自己开发了一个简单的ORM.我个人不喜欢EF因为跟不上EF升级太快了,再说公司里还停留在c# 3.5时代,对于NHibernate配置太复杂看到就头晕,就心生自己做一个ORM的 ...
- 一步步写STM32 OS【三】PendSV与堆栈操作
一.什么是PendSV PendSV是可悬起异常,如果我们把它配置最低优先级,那么如果同时有多个异常被触发,它会在其他异常执行完毕后再执行,而且任何异常都可以中断它.更详细的内容在<Cortex ...
- 从MySQL到ORM(三):连接、存储过程和用户权限
一.联结表 数据仍使用前文中的数据. 1.子查询 作为子查询的SELECT语句只能查询单个列.企图检索多个列将返回错误. -- 作为查询条件使用 -- 查看TNT2订单对应的客户ip(order表) ...
- Django ORM (三) 查询,删除,更新操作
ORM 查询操作 修改 views.py 文件 from django.shortcuts import render, HttpResponse from app01 import models f ...
- 一步步实现自己的ORM(五)
上一张优化了ORM的INSERT.UPDATE.DELETE,但将数据库里的值填充到实体类这块还没优化.另外有博友在网上咨询说你这个都是查询所有字段的,而他的需求是按需查询字段,不是一次性取出来所有字 ...
- 一步步实现自己的ORM(四)
通过前3章文章,大致对ORM有一定的了解,但也存在效率低下(大量用了反射)和重复代码,今天我们要对ORM进行优化. 具体流程如下: 我们优化的第一个就是减少反射调用,我的思路是定义一个Mapping, ...
- 13、Cocos2dx 3.0游戏开发找小三之3.0中的Director :郝萌主,一统江湖
重开发人员的劳动成果.转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27706967 游戏中的基本元素 在曾经文章中.我们具 ...
- 13、Cocos2dx 3.0三,找一个小游戏开发3.0中间Director :郝梦主,一统江湖
重开发人员的劳动成果.转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27706967 游戏中的基本元素 在曾经文章中,我们具 ...
随机推荐
- uglifyjs2全局混淆
从git克隆uglifyjs2源码后,进入目录: npm link 编译并安装uglifyjs2成功,就可以直接调用uglifyjs命令了.但是在进行全局混淆时出现了问题,虽然指定了文件topvar. ...
- CSS实现文字内容不被截断当超出指定长度时该字符串自动整体换到下一行
效果图: 1.内容不被截断 span { overflow:hidden; white-space:nowrap; text-overflow:ellipsis; ...
- ajax展示新页面同时传递参数
HTML页面部分代码: <div id="course" hidden></div> HTML页面中ajax代码: var selectType=$(&qu ...
- Python之线程与GIL
前言 以下内容是个人学习之后的感悟,转载请注明出处~ 线程是什么 线程是程序中一个单一的顺序控制流程.进程内一个相对独立的.可调度的执行单元,是系统独立调度和分派CPU的 基本单 ...
- java中关键字volatile的误解和使用
在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言是支持多线程的,为了解决线程并发的问题,在语 ...
- sql server 2008 R2 升级与安装遇到的问题
因工作需要,遂把以前的2008升级到r2,升级失败,具体原因忘了,卸载2008,清了注册表删了文件,结果安装的时候失败了,如下图: 下一步-有错误日志和错误的序列号,错误日志在C:\Program F ...
- 关于weblogic 10.3.6.0 的漏洞复现(2)
今天小R又学会了一个工具的使用,而且这个工具很强大很强大. 待会介绍. 一.需要的试验环境: 一台宿主机,虚拟机(kali+window2008或其他版本的windows) 1.宿主机需要的工具:B ...
- 算法学习--Day5
其实今天是第六天,不过昨天写的题目有些杂乱,都是贪心的算法,所以昨天的题目就不放上来了. 今天开始入手数据结构吧啦吧啦.. 数据结构当时学的时候感觉挺简单的,不过现在真正上代码之后发现情况并不妙,还是 ...
- [3dmax教程] 人物+骨骼+蒙皮+动画教程
人物+骨骼+蒙皮+动画完整教程选准备好一个人,做人的方法我在这里就不做了,大家可以学都用poser来做一个. 在大腿里建立4根骨骼! 在前视图中移动如图所示位置! 做一段简单的骨骼向前伸的动画,做4 ...
- 如何使得 python 脚本 不一闪而过
1. 简单的方法是在最后加上如下语句: os.system("pause") 2. 但是这个不一定有用,原因是可能在之前的代码中发生异常,那么我们看到的效果也是直接一闪而过 办法 ...