博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个简单得不能再简单的“ORM”了
阅读量:7117 次
发布时间:2019-06-28

本文共 7047 字,大约阅读时间需要 23 分钟。

本文适合初学者,老鸟请点赞即走,谢谢。

文字功底有限,表述不恰当的地方,请各位多多包涵。

一,核心

      现在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
paraName) { string sqlTag = sql; List
sqlParaName = new List
(); Regex regex = new Regex("(#(.[^#]+?)#)"); var ms = regex.Matches(sql); foreach (Match item in ms) { var p1 = item.Groups[1]; var p2 = item.Groups[2]; 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
paraName = new List
(); string sqlTag = SqlInit(sql, out paraName); IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count); for (int i = 0; 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
paraName = new List
(); string sqlTag = SqlInit(sql, out paraName); IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count); for (int i = 0; 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
paraName = new List
(); string sqlTag = SqlInit(sql, out paraName); object[] ht = (object[])para; IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count); for (int i = 0; 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
paraName = new List
(); string sqlTag = SqlInit(sql, out paraName); IDbDataParameter[] sqlParas = DBFactory.CreateDbDataParameters(type, paraName.Count); for (int i = 0; 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也太麻烦了吧,所以利用反射做了个实体转换器。

      (之前的文章)

    

public static T DataRowToModel
(DataRow row) { T model; Type type = typeof(T); ModelType modelType = GetModelType(type); switch (modelType) { case ModelType.Struct://值类型 { model = default(T); if (row[0] != null) model = (T)row[0]; } break; case ModelType.Enum://值类型 { model = default(T); if (row[0] != null) { Type fiType = row[0].GetType(); if (fiType == typeof(int)) { model = (T)row[0]; } else if (fiType == typeof(string)) { var value = Enum.Parse(typeof(T), row[0].ToString()); if (value != null) model = (T)value; } } } break; case ModelType.String://引用类型 c#对string也当做值类型处理 { model = default(T); if (row[0] != null) model = (T)row[0]; } break; case ModelType.Object://引用类型 直接返回第一行第一列的值 { model = default(T); if (row[0] != null) model = (T)row[0]; } break; case ModelType.Else://引用类型 { model = System.Activator.CreateInstance
();//引用类型 必须对泛型实例化 #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; }

 

 

 

 

好了,差不多了吧,还有些多谢没讲,可以看我另外两篇博客。

 

最后项目截图吧,稍后源码附上。

 

源码下载:

 

 

分类:
 
http://www.cnblogs.com/deeround/p/5670891.html
你可能感兴趣的文章
linux系统组成之小型RedHat little linux制作四
查看>>
我的友情链接
查看>>
How to Calculate Network and Broadcast Address
查看>>
通过7个python函数理解区块链
查看>>
Elasticsearch常用操作API
查看>>
Ambari 增加新的stack示例
查看>>
我的友情链接
查看>>
信息提示框:MessageBox
查看>>
教你用报表工具搭建企业考核系统
查看>>
321android浏览器
查看>>
find命令基本用法及练习
查看>>
ejabberd disable_sasl_mechanisms
查看>>
什么时候才能恢复我学习的心...
查看>>
Android零基础入门第12节:熟悉Android Studio界面,开始装逼卖萌
查看>>
export, import 和 export default的区别
查看>>
云场景实践研究第5期:朗新科技
查看>>
临近春节你为什么打不到车?概率论来帮忙!
查看>>
MySQL数据库基础操作
查看>>
C++模板别名的理解
查看>>
Elasticsearch在Hdfs上build的实现及优化
查看>>