一个简单得不能再简单的“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关键字前 ...
随机推荐
- 【腾讯Bugly干货分享】WebP原理和Android支持现状介绍
本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/582939577ef9c5b708556b0d 1.背景 目前网络中图片仍然是占 ...
- ASP.Net WebForm温故知新学习笔记:二、ViewState与UpdatePanel探秘
开篇:经历了上一篇<aspx与服务器控件探秘>后,我们了解了aspx和服务器控件背后的故事.这篇我们开始走进WebForm状态保持的一大法宝—ViewState,对其刨根究底一下.然后,再 ...
- Scrum Guide - Scrum指南中文版
现在公司在使用敏捷开发模式进行日常的开发和管理工作,所以我看了下Ken Schwaber的<Scrum Guide>这本小册子,原本是英文的,这里提供中文的,以供日后复习和参考. Scru ...
- 由乱序播放说开了去-数组的打乱算法Fisher–Yates Shuffle
之前用HTML5的Audio API写了个音乐频谱效果,再之后又加了个播放列表就成了个简单的播放器,其中弄了个功能是'Shuffle'也就是一般播放器都有的列表打乱功能,或者理解为随机播放. 但我觉得 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (33) ------ 第六章 继承与建模高级应用之TPH与TPT (2)
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-8 嵌套的TPH建模 问题 你想使用超过一层的TPH继承映射为一张表建模. 解 ...
- SQLite帮助类SQlitehelper 实现对SQLite数据的增删改查
public class SQLiteHelper { public const string sConn = "Data Source=" + @"path" ...
- ajax局部刷新后,如何让局部中的百度分享重新加载
我这个人不怎么喜欢说太多话,看几个图你们就懂了 Ajax前 Ajax之后 原因分析 解决方法 收工 百度分享是集成了众多主流第三方网站分享和收藏按钮的工具. 通过百度分享轻松将主流第三方网站的分享按钮 ...
- 传智播客--ADO.net--SqlBulkCopy批量插入数据(小白必知)
一般情况下,我们在向数据库中插入数据时用Insert语句,但是当数据量很大的时候,这种情况就比较缓慢了,这个时候就需要SqlBulkCopy这个类. SqlBulkCopy本身常用的函数有这么几个 D ...
- MVC实用架构设计(三)——EF-Code First(5):二级缓存
前言 今天我们来谈谈EF的缓存问题. 缓存对于一个系统来说至关重要,但是是EF到版本6了仍然没有见到有支持查询结果缓存机制的迹象.EF4开始会把查询语句编译成存储过程缓存在Sql Server中,据说 ...
- react+redux教程(三)reduce()、filter()、map()、some()、every()、...展开属性
reduce().filter().map().some().every()....展开属性 这些概念属于es5.es6中的语法,跟react+redux并没有什么联系,我们直接在https:// ...