一个ORM的实现(附源代码)
1 前言
经过一段时间的编写,终于有出来一个稳定的版本,期间考虑了多种解决方案也偷偷学了下园子里面大神们的作品。
已经有很多的ORM框架,为什么要自己实现一个?我的原因是在遇到特殊需求时,可以在ORM中加入特定的代码。如 :根据数据库的字段长度和可空性做基本的数据验证,在ORM中解决数据修改时的同步问题…
本文主要关注的是如何实现ORM方面,其它的大家可以参考以下两篇文章:
用T4 Template生成代码:参考此文,可以知道本ORM是如何根据数据库,生成实体层代码。有了这个基础,就可以看懂本文本中所有的T4模板。
DBHelper (支持事务与数据库变更):参考此文,可以知道本ORM是如何访问数据库,如何支持事务,分页和多种数据库。
2 实现方法
本文主要关注的蓝色ORM部分。
Model:定义了实体的基类。每一张表都会生成对应的实体并继承此类;
ModelMapping:定义了一张表的结构信息,其中包含了表名、主键、字段类型等。每一张表都会生成一个;
ModelMappingReflector: 在程序第一次运行时,反射所有ModelMapping的子类,并将其加入一个字典集合中;
DataAccess<T>: 此类的作用时,根据实体和实体的结构信息(ModelMapping),自动生成SQL来访问数据库(Add,Update,Delete);或将数据库中值加到实体上(GetModel,GetList)。此类帮我们做CRUD的工作,我们不再需要写每张表基本的增删改查的工作了,但仍需要写复杂业务的查询。每一张表都会生成一个空的dao类并继承此类。
此ORM的核心类就是DataAccess<T>, 下面我们就拿Add作为示例:
Add 操作代码
public int Add(T model)
{
if (model == null)
{
throw new ArgumentNullException();
} StringBuilder cmdText = new StringBuilder();
cmdText.Append("INSERT INTO ").Append(modelMapping.TableName).Append(" (");
cmdText.Append(string.Join(",", model.ColumnValues.Keys.ToArray()));
cmdText.Append(") VALUES (@");
cmdText.Append(string.Join(", @", model.ColumnValues.Keys.ToArray()));
cmdText.Append(")"); List<DbParameter> dbParms = new List<DbParameter>();
foreach (var pair in model.ColumnValues)
{
dbParms.Add(DBHelper.CreateInDbParameter(string.Format("@{0}",pair.Key), modelMapping.ColumnDict[pair.Key].DbDataBype, pair.Value));
} return this.ExecuteNonQuery(CommandType.Text, cmdText.ToString(), dbParms.ToArray());
}
当我们写这样的代码时User model=new User(); model.UserName时,实际上会向Model中ColumnValues集合中添加数据。而要生成一个INSERT SQL (INSERT INTO tablename (column1,colum2) VALUES (@column1,@column2)和添加插入参数,我们需要表名,列名,列值和列的类型。在列名和列值就存在于Model中的ColumnValues集合,而列的类型和表名,我们可以在ModelMapping中获取。
3 示例
static void Main(string[] args)
{
TestORM();
TestPaging(); Console.ReadLine();
} static void TestORM()
{
UserDao dao = new UserDao();
try
{
dao.BeginTransaction();
// add model
User mUser1 = new User();
mUser1.ID = "";
mUser1.UserName = "Mike1";
mUser1.UserPwd = "";
mUser1.CreateBy = "System";
mUser1.CreateDate = DateTime.Now;
dao.Add(mUser1); Console.WriteLine("Create Model Successfully.");
string cmdText = "SELECT * FROM TUser WHERE ID='1' ORDER BY ID;";
List<User> list0 = dao.GetListBySQL(cmdText);
foreach (User model in list0)
{
Console.WriteLine(model.UserName);
}
Console.WriteLine("Get List Successfully."); //嵌套事务
UserDao dao2 = new UserDao();
try
{
dao2.BeginTransaction();
//update model
User mUser2 = new User();
mUser2.ID = "";
mUser2.UserName = "Mike.Jiang";
mUser2.UserPwd = null;
mUser2.CreateDate = null;
dao.Update(mUser2);
Console.WriteLine("Update Model Successfully."); User mUser3 = dao.GetModel("");
if (mUser3 != null)
Console.WriteLine(mUser3.UserName); Console.WriteLine("Get Model Successfully.");
dao2.CommitTransaction();
}
catch
{
dao2.RollbackTransaction();
} dao.Delete(""); Console.WriteLine("Delete Model Successfully.");
dao.CommitTransaction();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
dao.RollbackTransaction();
}
} static void TestPaging()
{
UserDao dao = new UserDao();
// add 100 user
for (int i = ; i <= ; i++)
{
User mUser1 = new User();
mUser1.ID = i.ToString();
mUser1.UserName = "Mike" + i.ToString();
mUser1.UserPwd = "";
mUser1.CreateBy = "System";
mUser1.CreateDate = DateTime.Now;
dao.Add(mUser1);
} string cmdText = string.Format("SELECT * FROM TUser");
DataTable table = DBHelper.ExecutePagingDataTable(CommandType.Text, cmdText, , , "ORDER BY ID"); foreach (DataRow row in table.Rows)
{
Console.WriteLine(row["ID"]);
} Console.WriteLine("Get Datatabe paging successfuly."); List<User> list = dao.GetListPaging(cmdText, , , "ORDER BY ID");
foreach (User m in list)
{
Console.WriteLine(m.ID);
} Console.WriteLine("Get Model list paging successfully."); cmdText = "DELETE FROM TUser";
dao.ExecuteNonQuery(CommandType.Text, cmdText);
}
4 总结
这个版本的ORM示例,示例是没有认真去写了,因为不认为会有人用。但是这个ORM的代码是我认为比较简单的一个版本,只具有ORM的核心功能,几个类,只要具有c#基础的人都能看懂,有兴趣的可以看下。后续,自己会加上分页的Pager相关的内容、数据同步、数据验证的功能和和根据SQL自动生成实体对象的功能。
所有的源代码: BaseProject.7z
一个ORM的实现(附源代码)的更多相关文章
- 效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】) 转
效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中[附源代码下载]) 本文目录: (一)背景 (二)数据库数据导入到Excel的方法比较 ...
- 【转】P2P之UDP穿透NAT的原理与实现(附源代码)
作者:shootingstars (有容乃大,无欲则刚) 日期:2004-5-25 出处:P2P中国(PPcn.net) P2P 之 UDP穿透NAT的原理与实现(附源代码)原创:shootings ...
- 仿36氪(iOS版附源代码)
前言: 这是我2016年3月开始写的,利用课余时间全心投入的项目,本以为是凭着轻松愉悦的方式来学习的,中途遇到bug解决bug的时候,每天晚上几乎都是写到寝室关灯,还有一次使用Github不当写了五天 ...
- WCF技术剖析之二十八:自己动手获取元数据[附源代码下载]
原文:WCF技术剖析之二十八:自己动手获取元数据[附源代码下载] 元数据的发布方式决定了元数据的获取行为,WCF服务元数据架构体系通过ServiceMetadataBehavior实现了基于WS-ME ...
- Java设计模式-代理模式之动态代理(附源代码分析)
Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...
- Spring Web Flow 入门demo(三)嵌套流程与业务结合 附源代码
上篇博客我们说Spring web Flow与业务结合的方式主要有三种,以下我们主要介绍一下第三种的应用方式 3,运行到<action-state> 元素 SpringWeb Flow 中 ...
- 基于事件驱动的DDD领域驱动设计框架分享(附源代码)
原文:基于事件驱动的DDD领域驱动设计框架分享(附源代码) 补充:现在再回过头来看这篇文章,感觉当初自己偏激了,呵呵.不过没有以前的我,怎么会有现在的我和现在的enode框架呢?发现自己进步了真好! ...
- 手把手实现微信网页授权和微信支付,附源代码(VUE and thinkPHP)
wechat github 手把手实现微信网页授权和微信支付,附源代码(VUE and thinkPHP) 概述 公众号开发是痛苦的,痛苦在好多问题开发者文档是没有提到的,是需要你猜的. 在开发过程中 ...
- 介介介是一个ORM
介个是一个ORM,介个ORM基于Dapper扩展. 为什么需要一个ORM呢? 支持简单的LINQ查询 但是不能连表查询,why?why?why?为什么不能连接查询 ^.^ ok.但是就是不支持.哈哈哈 ...
- java程序保护如何知识产权,特别提供一个java 开发的java 源代码级的混淆器
java程序保护如何知识产权,特别提供一个java 开发的java 源代码级的混淆器 下载地址:http://yunpan.cn/QXhEcGNYLgwTD 运行方式:java -jar Encryp ...
随机推荐
- @@IDENTITY与SCOPE_IDENTITY()
在一条 INSERT.SELECT INTO 或大容量复制语句完成后,@@IDENTITY 中包含语句生成的最后一个标识值.如果语句未影响任何包含标识列的表,则 @@IDENTITY 返回 NULL. ...
- js中关于value的一个小知识点(value既是属性也是变量)
今天在学习input的value值时,发现这么一个小知识点,以前理解不太透彻. [1]以下这种情况是常见情况,会弹出“测试内容” <input type="button" v ...
- javascript学习目录
类型系统 [1]基本数据类型 [2]引用类型中的对象Object [3]引用类型中的数组Array [4]引用类型中的时间Date [5]函数Function [6]正则表达式RegExp [7]包装 ...
- 使用Ambari安装hadoop集群
最近需要做些spark的工作,所以弄了几台dell7500就这么准备开始搭建集群,之前用过几台更破的台式机搭建过一次,折腾了半个月之久,终于成功搭建,这次不想走老路,所以网上查了一下,发现一个神器AM ...
- PHP API接口测试小工具
前端时间给手机客户端做接口,当时弱爆了,写完API接口后,也不怎么测试,最后是等客户端调用的时候检验API的正确性. 后面利用PHP的curl实现Post请求,检验API接口的正确性:配合前面做的一个 ...
- 漫谈可视化Prefuse(二)---一分钟学会Prefuse
前篇<漫谈可视化Prefuse(一)---从SQL Server数据库读取数据>主要介绍了prefuse如何连接数据库sql server并读取数据进行可视化展现. 回头想想还是应该好好捋 ...
- 常用mysql数据库引擎——MyISAM和InnoDB区别
背景: 昨天做项目时,发现使用事务后回滚不了,后来把数据库引擎从MyISAM换成InnoDB后果断好了,如下图: 正文: MyISAM和InnoDB是mysql常用的数据库引擎,他们的区别如下: 数据 ...
- Eclipse快捷键大全(转载)
一.实用类快捷键 1 常用熟悉的快捷键 CTRL+C(复制).CTRL+X(剪切).CTRL+Z(撤销).CTRL+F(查找).CTRL+H(搜索文件或字符串).CTRL+Y(重做).CTRL+/(双 ...
- java虚拟机启动参数分类详解
官方文档见: http://docs.sun.com/source/819-0084/pt_tuningjava.html java启动参数共分为三类:其一是标准参数(-),所有的JVM实现都必须实现 ...
- UMeditor宽度自适应
百度编辑器UMeditor,生成富文本编辑框以后,改变窗口大小会出现横向滚动条,即使你调用接口设置了编辑器的宽度为100%.如: var um = UM.getEditor('<%=txtCon ...