一个简单得不能再简单的“ORM”了
本文适合初学者,老鸟请点赞即走,谢谢。
文字功底有限,表述不恰当的地方,请各位多多包涵。
一,核心
现在ORM已经很多了,功能也齐全了,大家说我这是干无聊的事,造的连车轮子都还不算,反正我就当学习。
还有就是,下面这个不算正在的ORM,离真正在ORM差的很远的。
主要思想

二,实例测试
1,基础数据准备
1.1 数据库表结构(sqlite数据库)

1.2 实体
public class Msg
{
public string Id { get; set; }
public string Content { get; set; }
public string Name { get; set; }
public DateTime CreateTime { get; set; }
}
2,开始插入数据
2.1 创建了一个控制台程序做测试
string connStr = string.Format("Data Source={0};", System.AppDomain.CurrentDomain.BaseDirectory + "App_Data\\db.db");
WangSql.ISqlExe sqlexe = new WangSql.SqlExe(WangSql.DbType.SQLLITE, connStr);
string sql = "insert into Msg(Id,Content,Name,CreateTime) values(#Id#,#Content#,#Name#,#CreateTime#)";
Msg model = new Msg()
{
Id = Guid.NewGuid().ToString("N"),
Content = "这里是内容",
Name = "姓名",
CreateTime = DateTime.Now
};
sqlexe.NonQuery(sql, model);
查看下数据呢,

至此,测试成功,再来测试下呢。
2.2 开8个线程,每个线程循环插入100条数据试试看。
测试结果:好尴尬sqlite多线程容易锁库,以后操作这个库,还是队列吧,楼主本着不放弃不抛弃的精神,再来了一次。

这次没被锁,数据库数据呢。

数据也没少,OK,测试完成。
三,源码讲解(准确的是代码讲解)
3.1 生成SQL
大家有没有发现,我在执行时传入sql的格式
insert into Msg(Id,Content,Name,CreateTime) values(#Id#,#Content#,#Name#,#CreateTime#)//有没有很熟悉呢,没错,就是借鉴(山寨)的ibatis的,哈哈
就是这个样子的,
表:Msg(Id,Content,Name,CreateTime)
DbDataParameter:values(#Id#,#Content#,#Name#,#CreateTime#)
DbDataParameter,这里支持值类型,string,object,object[],以及Hashtable和用户自定义类。
下面就是生成SQL语句的代码、
public string SqlInit(string sql, out List<string> paraName)
{
string sqlTag = sql;
List<string> sqlParaName = new List<string>();
Regex regex = new Regex("(#(.[^#]+?)#)");
var ms = regex.Matches(sql);
foreach (Match item in ms)
{
var p1 = item.Groups[];
var p2 = item.Groups[];
sqlTag = sqlTag.Replace(p1.Value, prefix + p2.Value);
if (!sqlParaName.Contains(p2.Value))
sqlParaName.Add(p2.Value);
}
paraName = sqlParaName;
return sqlTag;
}
这个就会生成sql,并且还会把Parameter的key以集合的方式抛出去。
3.2 实体转成DbDataParameter
当插入数据,参数传入的是个用户自定义类的话,需要做一次转换。先将实体转成Hashtable,然后再根据3.1生成sql抛出来的Parameter的key来生成Parameter集合。
public static Hashtable ModelToHashtable(object model)
{
Hashtable ht = new Hashtable();
BindingFlags flag = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
PropertyInfo[] propertys = model.GetType().GetProperties(flag);
foreach (PropertyInfo pi in propertys)
{
string name = pi.Name;
if (!pi.CanRead) continue;
object value = pi.GetValue(model, null);
ht.Add(name, value);
}
return ht;
}
3.3 完整NonQuery执行代码
public int NonQuery(string sql, object para)
{
if (IsModel(para))//Model入参
{
Hashtable ht = DataMapHelper.ModelToHashtable(para);
List<string> paraName = new List<string>();
string sqlTag = SqlInit(sql, out paraName);
IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count);
for (int i = ; i < paraName.Count; i++)
{
string key = paraName[i];
object value = ht[key];
sqlParas[i] = DBFactory.CreateDbDataParameter(type, prefix + key, value);
}
var result = helper.ExecuteNonQuery(sqlTag, sqlParas);
return result;
}
else if (para.GetType() == typeof(Hashtable))//Hashtanle入参
{
Hashtable ht = (Hashtable)para;
List<string> paraName = new List<string>();
string sqlTag = SqlInit(sql, out paraName);
IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count);
for (int i = ; i < paraName.Count; i++)
{
string key = paraName[i];
object value = ht[key];
sqlParas[i] = DBFactory.CreateDbDataParameter(type, prefix + key, value);
}
var result = helper.ExecuteNonQuery(sqlTag, sqlParas);
return result;
}
else if (para.GetType() == typeof(object[]))
{
List<string> paraName = new List<string>();
string sqlTag = SqlInit(sql, out paraName);
object[] ht = (object[])para;
IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count);
for (int i = ; i < paraName.Count; i++)
{
string key = paraName[i];
object value = ht[i];
sqlParas[i] = DBFactory.CreateDbDataParameter(type, prefix + key, value);
}
var result = helper.ExecuteNonQuery(sqlTag, sqlParas);
return result;
}
else//一个参数入参
{
List<string> paraName = new List<string>();
string sqlTag = SqlInit(sql, out paraName);
IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count);
for (int i = ; i < paraName.Count; i++)
{
string key = paraName[i];
object value = para;
sqlParas[i] = DBFactory.CreateDbDataParameter(type, prefix + key, value);
}
var result = helper.ExecuteNonQuery(sqlTag, sqlParas);
return result;
}
}
3.4 查询语句
如果是查询的话,执行完SQL返回一个DataTable,操作DataTable也太麻烦了吧,所以利用反射做了个实体转换器。
DataTable转实体Model,DataRow转实体Model,DataTable转泛型T,DataRow转泛型T (之前的文章)
public static T DataRowToModel<T>(DataRow row)
{
T model;
Type type = typeof(T);
ModelType modelType = GetModelType(type);
switch (modelType)
{
case ModelType.Struct://值类型
{
model = default(T);
if (row[] != null)
model = (T)row[];
}
break;
case ModelType.Enum://值类型
{
model = default(T);
if (row[] != null)
{
Type fiType = row[].GetType();
if (fiType == typeof(int))
{
model = (T)row[];
}
else if (fiType == typeof(string))
{
var value = Enum.Parse(typeof(T), row[].ToString());
if (value != null)
model = (T)value;
}
}
}
break;
case ModelType.String://引用类型 c#对string也当做值类型处理
{
model = default(T);
if (row[] != null)
model = (T)row[];
}
break;
case ModelType.Object://引用类型 直接返回第一行第一列的值
{
model = default(T);
if (row[] != null)
model = (T)row[];
}
break;
case ModelType.Else://引用类型
{
model = System.Activator.CreateInstance<T>();//引用类型 必须对泛型实例化
#region MyRegion
//获取model中的属性
BindingFlags flag = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
PropertyInfo[] modelPropertyInfos = type.GetProperties(flag);
//遍历model每一个属性并赋值DataRow对应的列
foreach (PropertyInfo pi in modelPropertyInfos)
{
if (!pi.CanWrite) continue;
//获取属性名称
string tempName = GetFieldName(pi);
String name = string.IsNullOrEmpty(tempName) ? pi.Name : tempName;
if (row.Table.Columns.Contains(name) && row[name] != null)
{
ModelType piType = GetModelType(pi.PropertyType);
switch (piType)
{
case ModelType.Struct:
{
var value = Convert.ChangeType(row[name], pi.PropertyType);
pi.SetValue(model, value, null);
}
break;
case ModelType.Enum:
{
Type fiType = row[name].GetType();
if (fiType == typeof(int))
{
pi.SetValue(model, row[name], null);
}
else if (fiType == typeof(string))
{
var value = Enum.Parse(typeof(T), row[name].ToString());
if (value != null)
pi.SetValue(model, (T)value, null);
}
}
break;
case ModelType.String:
{
var value = Convert.ChangeType(row[name], pi.PropertyType);
pi.SetValue(model, value, null);
}
break;
case ModelType.Object:
{
pi.SetValue(model, row[name], null);
}
break;
case ModelType.Else:
//throw new Exception("不支持该类型转换");
break;
default:
throw new Exception("未知类型");
}
}
}
#endregion
}
break;
default:
model = default(T);
break;
} return model;
}
好了,差不多了吧,还有些多谢没讲,可以看我另外两篇博客。
DataTable转实体Model,DataRow转实体Model,DataTable转泛型T,DataRow转泛型T
最后项目截图吧,稍后源码附上。

源码下载:
一个简单得不能再简单的“ORM”了的更多相关文章
- Python入门一:简单得不能再简单了##
从python的语法上看,简单得不能再简单了. 想学它,请移步廖雪峰python2.7教程以及python3.这实在是最好的入门教程.参考资料太多: 外国的教程 Python 入门指南 Python ...
- C# 实现IP视频监控(摄像头)画面推送(简单的不能再简单的DEMO)
最近继续在家休息,在完成上一个Python抓取某音乐网站爬虫后,琢磨着实现一个基于HTTP推送的 IP视频监控,比如外出的时候,在家里 开启一个监控端(摄像头+服务端),可以看到实时画面,如果再加上自 ...
- grunt配置太复杂?发布一个前端构建工具,简单高效,自动跳过未更新的文件
做前端项目,如果没有一个自动化构建工具,手动处理那简直就是坑爹O(∩_∩)O.于是上网了解了下,grunt用的人不少,功能也挺强大.看了一下grunt的配置(包括gulp),感觉稍显复杂.当时项目结构 ...
- 写一个ajax程序就是如此简单
写一个ajax程序就是如此简单 ajax介绍: 1:AJAX全称为Asynchronous JavaScript and XML(异步JavaScript和XML),指一种创建交互式网页应用的网页开发 ...
- Android图表库MPAndroidChart(七)—饼状图可以再简单一点
Android图表库MPAndroidChart(七)-饼状图可以再简单一点 接上文,今天实现的是用的很多的,作用在统计上的饼状图,我们看下今天的效果 这个效果,我们实现,和之前一样的套路,我先来说下 ...
- 手撸一个SpringBoot的Starter,简单易上手
前言:今天介绍一SpringBoot的Starter,并手写一个自己的Starter,在SpringBoot项目中,有各种的Starter提供给开发者使用,Starter则提供各种API,这样使开发S ...
- Bitter ORM NETCORE ORM 全网最粗暴简单易用高性能的 NETCore ORM 开源了
开源的来了,懒人程序员的福音,.NET 生态闭环太缺开源精神了, 拥抱开源! 前言: 本人不是不喜欢现有ORM的轮子,而是发现现有的ORM 的都不太符合开发人员的一些习惯.现有的ORM 要么功能太冗余 ...
- VB.net数据库编程(03):一个SQLserver连接查询的简单样例
这个样例,因为在ADO.net入门已经专门学了,再次进行复习 一下. 主要掌握连接字串的情况. 过程就是: 1.引用System.Data.SqlClient.而Access中引用 的是System. ...
- 【转】C#类的分类(静态类、实例类、嵌套类、结构、简单的抽象类、简单的密封类)
静态类 -------------------------------------------------------------------------------- 静态类就是在class关键字前 ...
随机推荐
- Java多线程7:死锁
前言 死锁单独写一篇文章是因为这是一个很严重的.必须要引起重视的问题.这不是夸大死锁的风险,尽管锁被持有的时间通常很短,但是作为商业产品的应用程序每天可能要执行数十亿次获取锁->释放锁的操作,只 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (25) ------ 第五章 加载实体和导航属性之加载完整的对象图和派生类型上的导航属性
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-5 加载完整的对象图 问题 你有一个包含许多关联实体的模型,你想在一次查询中, ...
- Html5 布局方式
在Html5之前,统一采用的是Div+css的方式进行布局,但是却和开发人员的命名方式,喜好有关.在新的Html5中,布局却显得更加人性化,更易理解了.如增加了Header,Footer,Sectio ...
- Eclipse启动参数
from 网络 eclipse 启动参数 -clean2013-- : eclipse 启动参数介绍(如添加插件时,如果不显示,则使用eclipse -clean启动) 其实,Eclipse是一个可以 ...
- [Hadoop大数据]——Hive初识
Hive出现的背景 Hadoop提供了大数据的通用解决方案,比如存储提供了Hdfs,计算提供了MapReduce思想.但是想要写出MapReduce算法还是比较繁琐的,对于开发者来说,需要了解底层的h ...
- Mycat配置及使用详解.
首先我们来看下什么是Mycat:MyCat:开源分布式数据库中间件, 这里定义的很简单, 就是分布式数据库的中间件. 其实Mycat 是可以时mysql进行集群的中间件, 我们可以对mysql来分库分 ...
- Dynatree使用
最近用到了Dynatree的树形结构,记录一下它的用法. 需求: 1.jquery.js 2.jquery-ui.custom.js 3.jquery.cookie.js 下载dynatree,放到资 ...
- 深入浅出Hyper-V网络虚拟化技术
年后综合症刚刚消失殆尽,转眼就要迎接各种新的工作任务了:之前写过一篇有关hyper-v网络虚拟化内容的博文,主要是从操作系统层面入手,概要性的总结了一下,基本也都是参考了大部分官方内容再加以个人修饰: ...
- Polynomial Library in OpenCascade
Polynomial Library in OpenCascade eryar@163.com 摘要Abstract:分析幂基曲线即多项式曲线在OpenCascade中的计算方法,以及利用OpenSc ...
- MySql事务概述
事务是访问并更新数据库中各种数据项的一个程序执行单元.在事务中的操作,要么都执行修改,要么都不执行,这就是事务的目的,也是事务模型区别于文件系统的重要特征之一. 严格上来说,事务必须同时满足4个特性, ...