一步步实现自己的ORM(一)
最近在研究ORM,尝试着自己开发了一个简单的ORM。我个人不喜欢EF因为跟不上EF升级太快了,再说公司里还停留在c# 3.5时代,对于NHibernate配置太复杂看到就头晕,就心生自己做一个ORM的念头,现在把开发过程中的点点滴滴记录下来,供自己和新手参考,大神请直接忽略这篇文章。
ORM(object relation mapping)对象关系映射,常用来映射数据库里表、字段等信息。ORM的原理无非就是用配置文件、Attribute来映射数据关系。我们一步步来来创建ORM,定义一个实体类,然后用反射获得类名(表名)、属性(对应是字段名称),例子如下:
CREATE TABLE [dbo].[User](
[UserId] [int] NOT NULL primary key,
[Email] [nvarchar](100) NULL,
[CreatedTime] [datetime] NULL
)
在这里我创建一张表,其中UserId是主键,为什么不定义成自增长的呢?请保留这个疑问,继续看下去。表创建好了,下面就是定义一个类,如下:
public class User
{
public int UserId { get; set; } public string Email { get; set; } public DateTime CreatedTime { get; set; }
}
现在我们要对这个类写一个INSERT操作,直接传入User对象然后插入到数据库。我们要用系统自动构建SQL语句,不需要手写SQL语句,在这我们先分析下INSERT INTO SQL语句。
INSERT INTO 表名
(字段1
,字段2
,字段3...)
VALUES
值1,
值2,
值3...
我们需要知道表名、字段名和值才能够完成SQL拼接,怎么得到这些信息呢,万能的反射该出场。
string className = typeof(User).Name;
Console.WriteLine("类名:{0}", className);
Console.WriteLine("-----获取属性信息-----");
var properties = typeof(User).GetProperties();
foreach (var item in properties)
{
Console.WriteLine("属性名:{0}",item.Name);
}
Console.WriteLine("-----end-----");
运行结果如下

LOOK,User类的信息都显示出来了,属性的值该如何显示?也就是SQL语句的VALUE,还是要靠万能的反射,请看官门继续往下看。
string className = typeof(User).Name;
Console.WriteLine("类名:{0}", className);
var properties = typeof(User).GetProperties();
User user = new User() {
UserId = ,
Email = "abc@123.com",
CreatedTime = DateTime.Now
}; foreach (var item in properties)
{
Console.WriteLine("{0}:{1}", item.Name, item.GetValue(user, null));
}

类名、属性名、属性值我们都得到了,那下面要做的就是拼写SQL语句了
public static void Main()
{
PritSql(new User()
{
UserId = ,
Email = "abc@123.com",
CreatedTime = DateTime.Now
}); } public static void PritSql(User user)
{ string className = typeof(User).Name;
var properties = typeof(User).GetProperties(); StringBuilder sql = new StringBuilder();
sql.Append("INSERT INTO ").Append(className).Append("("); for (int i = ; i < properties.Length; i++)
{
var pi = properties[i];
if (i > )
sql.Append(",");
sql.Append(pi.Name);
}
sql.Append(") VALUES (");
for (int i = ; i < properties.Length; i++)
{
var pi = properties[i];
if (i > )
sql.Append(",");
sql.Append("'").Append(pi.GetValue(user,null)).Append("'");
}
sql.Append(")");
Console.WriteLine(sql); }

为避免SQL注入,我把SQL改成参数的信息
INSERT INTO 表名
(字段1
,字段2
,字段3...)
VALUES
@p1,
@p2,
@p3...
修改后的c#代码
public static void Main()
{
PritParameterSql(new User()
{
UserId = ,
Email = "abc@123.com",
CreatedTime = DateTime.Now
}); }
public static int PritParameterSql<T>(T user)
{
Dictionary<string, object> parameters = new Dictionary<string, object>();
string className = typeof(T).Name;
var properties = typeof(T).GetProperties(); StringBuilder sql = new StringBuilder();
sql.Append("INSERT INTO [").Append(className).Append("]("); for (int i = ; i < properties.Length; i++)
{
var pi = properties[i];
if (i > )
sql.Append(",");
sql.Append(pi.Name);
}
sql.Append(") VALUES (");
for (int i = ; i < properties.Length; i++)
{
var pi = properties[i];
if (i > )
sql.Append(",");
sql.Append("@p").Append(i); parameters.Add("@p" + i, pi.GetValue(user, null));
}
sql.Append(")");
Console.WriteLine(sql); SqlConnection conn = new SqlConnection(connectionString);
var cmd = conn.CreateCommand();
cmd.CommandText = sql.ToString();
foreach (var item in parameters)
{
var pa = cmd.CreateParameter();
pa.ParameterName = item.Key;
pa.Value = item.Value ?? DBNull.Value;
cmd.Parameters.Add(pa);
} conn.Open();
return cmd.ExecuteNonQuery();
}
执行后的结果


还记得前面提到为什么UserId不设置成自增长吗?因为这种单纯的反射无法识别哪个是自增长字段,如果想用自增长主键怎么办?请看后续文章。
一步步实现自己的ORM(一)的更多相关文章
- 一步步实现自己的ORM(二)
在第一篇<一步步实现自己的ORM(一)>里,我们用反射获取类名.属性和值,我们用这些信息开发了简单的INSERT方法,在上一篇文章里我们提到主键为什么没有设置成自增长类型,单单从属性里我们 ...
- 一步步实现自己的ORM(三)
章节列表: <一步步实现自己的ORM(一)> <一步步实现自己的ORM(二)> 通过前面两篇文章,我们大致了解了ORM的基本原理,是通过Attribute+反射获取表的基本信息 ...
- 一步步实现自己的ORM(五)
上一张优化了ORM的INSERT.UPDATE.DELETE,但将数据库里的值填充到实体类这块还没优化.另外有博友在网上咨询说你这个都是查询所有字段的,而他的需求是按需查询字段,不是一次性取出来所有字 ...
- 一步步实现自己的ORM(四)
通过前3章文章,大致对ORM有一定的了解,但也存在效率低下(大量用了反射)和重复代码,今天我们要对ORM进行优化. 具体流程如下: 我们优化的第一个就是减少反射调用,我的思路是定义一个Mapping, ...
- Moon.Orm 常见查询实例
一.Moon.Orm框架总述 (您还用hibernate?实体框架?) 1.框架名:Moon 意思是月亮,而非Mono.因为很喜欢明月,所以以此为名.它是一个.NET下的Orm框架. 2.发展历史:历 ...
- Mini ORM——PetaPoco笔记
Mini ORM--PetaPoco笔记 记录一下petapoco官网博客的一些要点.这些博客记录了PetaPoco是如何一步步改进的. 目录: Announcing PetaPoco PetaPoc ...
- Moon.Orm 5.0(MQL版)及之前版本的开源计划
开源综述:步步开源 Moon.Orm 5.0 (MQL版) 版本维护及下载 (跟踪发布) Moon.Orm 5.0系列文章 Moon.Orm 5.0性能问题,将发言权交给你! 一.5.0目前的情况,步 ...
- .NET ORM 的 “SOD蜜”--零基础入门篇
PDF.NET SOD框架不仅仅是一个ORM,但是它的ORM功能是独具特色的,我在博客中已经多次介绍,但都是原理性的,可能不少初学的朋友还是觉得复杂,其实,SOD的ORM是很简单的.下面我们就采用流行 ...
- Mini ORM——PetaPoco笔记(转)
记录一下petapoco官网博客的一些要点.这些博客记录了PetaPoco是如何一步步改进的. 目录: Announcing PetaPoco PetaPoco-Improvements PetaPo ...
随机推荐
- rkhunter和chkrootkit
今天继续检查我的Linux,所以下来rkhunter和chkrootkit一个一个来,下面只记录命令,少些说明不截图了. 1.rkhunter #cd /temp #wget http://downl ...
- 使用 WinSCP(下载) 上文件到 Linux图文教程
问题导读: 1.如何远程链接? 2.如何上传文件? 3.如何对立面的文件进行操作? 4.什么情况下会链接失败? https://yunpan.cn/cYWtNMycjeVPv 访问密码 4f7 ...
- yolo-开源数据集coco kitti voc
1.kitti数据集(参考博客:https://blog.csdn.net/jesse_mx/article/details/65634482 https://blog.csdn.net/baoli ...
- c# aop讲解
先说下场景,C#中为什么要使用Aop,而我又是在哪里使用Aop? 本人只是想拦截实体类的Set的方法,然后在Set之前,调用一下其它方法,把值赋给另一个对象. 而我做的都是在实体类的基类里处理: 比如 ...
- SSIS 事务
本文摘自:http://www.cnblogs.com/tylerdonet/archive/2011/09/23/2186579.html 在这一个随笔中将介绍在package中如何使用事务来保证数 ...
- 揭开 iOS 7 之 Multipath TCP 的面纱(转)
看到中文圈似乎讨论 iOS 7 的这个特性的还不多,于是我稍微研究了一下这个「Mutlipath TCP」,写点心得.过程是这样的: Olivier Bonaventure 通过 Wireshark ...
- eclipse修改某一个项目的字符编码
eclipse修改某一个项目的字符编码 1 选中要修改编码的文件,鼠标右键,选择[Properties] 2 左侧选中[Resource], 右侧出现[Text file encoding], ...
- CodeForces 359D Pair of Numbers (暴力)
题意:给定一个正整数数组,求最长的区间,使得该区间内存在一个元素,它能整除该区间的每个元素. 析:暴力每一个可能的区间,从数组的第一个元素开始考虑,向两边延伸,设延伸到的最左边的点为l, 最右边的点为 ...
- 201621123016《Java程序设计》第1周学习总结
1. 本周学习总结 本周的学习内容:java的发展历史,java程序设计环境,java简单语法. java与c++一样是一门面向对象的程序设计语言(相比于c++它是一门更彻底的面向对象的程序设计语言) ...
- 阿里巴巴开源性能监控神器Arthas初体验
如果问性能测试中最难的是哪部分,相信很多人会说“性能调优”.确实是这样,性能调优是一个非常复杂.技术含量很高的工作.涉及到的知识面很广.以我多年从业经验来看,在企业里,大多数的性能调优都是由开发架构师 ...