快速传送

手撸ORM浅谈ORM框架之基础篇

手撸ORM浅谈ORM框架之Add篇

手撸ORM浅谈ORM框架之Update篇

手撸ORM浅谈ORM框架之Delete篇

手撸ORM浅谈ORM框架之Query篇

后续待定。。。。。。

合抱之木,生于毫末

反射

在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。

手撸ORM浅谈ORM框架系列使用反射机制来实现的动态获取所需要的信息,反射机制有优点也有缺点,使用了反射我们可以不用每次更新实体模型数据访问层转换Sql等很多需要修改的地方,享受快捷便利的同时肯定会带来相应的缺点,反射的性能在执行同样的操作时会略低于直接使用强类型语言的原生特性,毕竟它至少多了动态获取信息步骤;我们不能因此否认反射,反射确实在很多场景可以为我们做很多不必要的重复性工作,可以节约出时间做更棘手的问题。

对于我们需要使用什么决定因素需要看使用前后的变化,利大于弊且符合业务需要就放心使用,完美不存在,更美从未止步。。。

泛型

泛型(摘录百度百科:泛型)

由于.NET Framework 泛型的类型参数之实际类型在运行时均不会被消除,运行速度会因为类型转换的次数减少而加快。Java 泛型的参数只可以代表类,不能代表个别对象。由于 Java 泛型的类型参数之实际类型在编译时会被消除,所以无法在运行时得知其类型参数的类型。Java 编译器在编译泛型时会自动加入类型转换的编码,故运行速度不会因为使用泛型而加快。

九层之台,起于累土

主要通过反射获取实体信息,目前项目中的实体唯一主键统一使用的bigint自动递增。

BaseRepository-》GetCurrentTableName获取表名称;

 1 /// <summary>
2 /// get current-table-name
3 /// </summary>
4 /// <returns>return table-name</returns>
5 private string GetCurrentTableName()
6 {
7 string currentTableName = string.Empty;
8 var t = typeof(T);
9 if (t != null && !t.Name.IsNullOrEmpty())
10 {
11 currentTableName = t.Name;
12 }
13 if (currentTableName.IsNullOrEmpty())
14 {
15 throw new ArgumentNullException("get table-name is null");
16 }
17 return currentTableName;
18 }

BaseRepository-》GetExcludeKeyAllFields获取主键以外的public字段;

 1 /// <summary>
2 /// get exclude key all fields
3 /// </summary>
4 /// <returns>return exclude key all fields</returns>
5 private List<PropertyInfo> GetExcludeKeyAllFields()
6 {
7 PropertyInfo[] properties = typeof(T).GetProperties();
8 // filter abstract virtual property
9 properties = properties.Where(p => p.PropertyType.IsAbstract == false && !p.GetMethod.IsVirtual == true).ToArray();
10 if (properties == null || properties.Length <= 0)
11 {
12 throw new ArgumentNullException("public value fields is null");
13 }
14 List<PropertyInfo> list = new List<PropertyInfo>();
15 foreach (var item in properties)
16 {
17 if (item.CustomAttributes.Any(c => c.AttributeType.Name == nameof(KeyAttribute)))
18 {
19 continue;
20 }
21 list.Add(item);
22 }
23 if (list == null || list.Count <= 0)
24 {
25 throw new ArgumentNullException("public value fields is null");
26 }
27 return list;
28 }

BaseRepository-》GetValue获取字段对应的值,String和Char前面分别加了N前缀(Sql Server反射弧),MySql中文字符可加或不加中文字段不会出现乱码,若出现乱码可以根据实际情况设置MySql数据库字符集的格式;

 1 /// <summary>
2 /// get value
3 /// </summary>
4 /// <param name="property"></param>
5 /// <param name="entity"></param>
6 /// <returns></returns>
7 private string GetValue(PropertyInfo property , T entity)
8 {
9 var val = property.GetValue(entity);
10 if (val == null)
11 {
12 return "NULL";
13 }
14 else
15 {
16 string prefixN = string.Empty;
17 if (property.PropertyType.Name == nameof(String) || property.PropertyType.Name == nameof(Char))
18 {
19 prefixN = "N";
20 }
21 if (property.PropertyType.Name == nameof(Boolean))
22 {
23 return string.Format("{0}", GetBoolValue(val));
24 }
25 return string.Format("{0}'{1}'", prefixN, val);
26 }
27 }

BaseRepository-》GetBoolValue值属性转换,Sql Server中数据类型bit:'true' or 'false' 等同于'1' or '0';MySql 8.x数据类型bit: 需要把bool 'true' or 'false' 转换成'1' or '0' 。目前项目中使用到的数据类型bigint、varchar、int、char、datetime、bit,bit->需要转换;

 1 /// <summary>
2 /// get bool value
3 /// mysql true or false convert 1 or 0
4 /// </summary>
5 /// <param name="obj"></param>
6 /// <returns></returns>
7 private int GetBoolValue(object obj)
8 {
9 //return obj.ToString().ToLower() == "false" ? 0 : 1;
10 if (obj.ToString().ToLower() == "false")
11 {
12 return 0;
13 }
14 return 1;
15 }

BaseRepository-》GetInsertSql一路走来Sql出现了(提高性能可以优化,缓存当前项目所有表的增删查改Sql语句)

 1 /// <summary>
2 /// get insert sql
3 /// </summary>
4 /// <param name="entity">entity</param>
5 /// <returns>return insert sql</returns>
6 private string GetInsertSql(T entity)
7 {
8 string tableName = GetCurrentTableName();
9 StringBuilder sbField = new StringBuilder();
10 StringBuilder sbValue = new StringBuilder();
11 PropertyInfo[] properties = GetAllFields(true);
12 foreach (var item in properties)
13 {
14 sbField.AppendFormat("{0},", item.Name);
15 sbValue.AppendFormat("{0},", GetValue(item, entity));
16 }
17 sbField.Remove(sbField.Length - 1, 1);
18 sbValue.Remove(sbValue.Length - 1, 1);
19 //todo ;SELECT @@identity return identity
20 return string.Format("INSERT INTO {0} ({1}) VALUES ({2})", tableName, sbField, sbValue);
21 }

BaseRepository-》Add千呼万唤始出来,终于到写入数据库了(Add成功后没有返回实体因为NET Core的DbContext取消了SqlQuery,基类BaseRepository实现Add后返回当前的实体主键,基本原生 SQL 查询可使用 FromSqlRaw 扩展方法基于原始 SQL 查询开始 LINQ 查询。 FromSqlRaw 只能在直接位于 DbSet<> 上的查询根上使用;NET Framework DBContext中有此方法SqlQuery,可以使用Query在Insert语句后面;SELECT @@identity返回int、bigint类型自动递增主键并赋值给当前实体,如果是指定主键直接返回当前实体,也期待园友提出更好的解决方案)

 1 /// <summary>
2 /// add entity
3 /// </summary>
4 /// <param name="entity">entity</param>
5 /// <returns>return true or false</returns>
6 public bool Add(T entity)
7 {
8 string sql = GetInsertSql(entity);
9 context.Database.ExecuteSqlRaw(sql);
10 return true;
11 }

实操Repository方法泛型约束

 1 /// <summary>
2 /// LearnStudentRepository
3 /// </summary>
4 public partial class LearnStudentRepository: ILearnStudentRepository
5 {
6 public bool Add(Learn_Student learnStudent)
7 {
8 using (MySqlDbContext mySqlDbContext=new MySqlDbContext())
9 {
10 BaseRepository<Learn_Student> baseRepository = new BaseRepository<Learn_Student>(mySqlDbContext);
11 return baseRepository.Add(learnStudent);
12 }
13 }
14 }

登高望远,更上层楼

learn-orm-net缺少以下情况的处理:

  • 1. Sql语句没有缓存,缓存提高一些性能;
  • 2.不支持指定主键的实体,既是已经提前把主键生成好了;
  • 3.项目使用的实体是自动递增主键并且没有返回主键的值,不能满足主子表有外键关系业务场景,既是子表存主表的主键(自动递增类型主键);
  • 4.复合主键(主键都是指定主键,提前按照一定规则生成的键值);
  • 5.复合主键里面包含自增主键,既是有指定类型主键也有自动递增类型主键;
  • 6.实体包含导航属性级联写入数据库(类似于3)
  • (如果业务需要特殊的方式,ORM框架没有我们可以写基类方法或者扩展方法来适应项目需要,待补充...)
  • 注:learn-orm-net目前只是作为学习ORM框架原理的Demo,项目会做出一定的优化处理,但不能直接拿来在项目中使用,毕竟现在NET Framework、NET Core已经有很多优秀的ORM框架,NET下一次发布就是只有一个版本了,我们没有必要重复造轮子,造轮子是因为没有现成的优秀的轮子可用。

如果只是停留在会使用当前项目所使用的ORM框架基本增删查改,对于根据业务更好的使用ORM框架是有点困难的;所以,深入理解ORM原理,为未来的某个时刻我们遇到了问题,更好的根据ORM框架有的功能做出比较符合业务需要的程序;或者,扩展当前ORM框架没有的功能来适应我们项目的业务需求。

代码下载地址: SourceCode  作者水平有限欢迎园友纠正错误及不恰当之处,予以及时修正以免误导他人!

手撸ORM浅谈ORM框架之Add篇的更多相关文章

  1. 手撸ORM浅谈ORM框架之基础篇

    好奇害死猫 一直觉得ORM框架好用.功能强大集众多优点于一身,当然ORM并非完美无缺,任何事物优缺点并存!我曾一度认为以为使用了ORM框架根本不需要关注Sql语句如何执行的,更不用关心优化的问题!!! ...

  2. 手撸ORM浅谈ORM框架之Update篇

    快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...

  3. 手撸ORM浅谈ORM框架之Delete篇

    快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...

  4. 手撸ORM浅谈ORM框架之Query篇

    快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...

  5. 手撸基于swoole 的分布式框架 实现分布式调用(20)讲

    最近看的一个swoole的课程,前段时间被邀请的参与的这个课程 比较有特点跟一定的深度,swoole的实战教程一直也不多,结合swoole构建一个新型框架,最后讲解如何实现分布式RPC的调用. 内容听 ...

  6. 【SSH学习笔记】浅谈SSH框架

    说在前面 本学期我们有一门课叫做Java EE,由陈老师所授,主要讲的就是Java EE 中的SSH框架. 由于陈老师授课风格以及自己的原因导致学了整整一学期不知道在讲什么,所以才有了自己重新学习总结 ...

  7. 浅谈chainer框架

    一 chainer基础 Chainer是一个专门为高效研究和开发深度学习算法而设计的开源框架. 这篇博文会通过一些例子简要地介绍一下Chainer,同时把它与其他一些框架做比较,比如Caffe.The ...

  8. 浅谈ORM操作

    2. ORM(对象关系映射) 1. 映射的关系 DB ORM 数据表 <--> 类 数据行 <--> 对象 字段 <--> 属性 2. Django项目使用MySQ ...

  9. 【带你手撸Spring】没有哪个框架开发,能离开 Spring 的 FactoryBean!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 老司机,你的砖怎么搬的那么快? 是有劲?是技巧?是后门?总之,那个老司机的代码总是可 ...

随机推荐

  1. Fork Join 并发任务执行框架

    Fork Join 体现了分而治之 什么是分而治之? 规模为N的问题,如果N<阈值,直接解决,N>阈值,将N分解为K个小规模子问题,子问题互相对立,与原问题形式相同,将子问题的解合并得到原 ...

  2. 接口、RESTful规范、DRF

    接口 #接口:url连接,通过向链接发送不同的类型请求与参数得到相应的响应数据 #1.在视图书写处理请求的 视图函数 #2.在路由层为视图函数配置 url链接=>产生接口 #3.前台通过ajax ...

  3. Aop的学习与使用

    什么是aop AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一 ...

  4. SpringBoot整合MongoDB(实现一个简单缓存)

    前言 SpringBoot是常用开发框架,而MongoDB也是最近越来越火的非关系型数据库,这里使用SpringBoot+MongoDB实现一个小案例,当然MongoDB实际做缓存的可能不多,但是这里 ...

  5. mysql load_file()

    本地mysql注入读取配置文件 遇到的问题 简单记录一下. 本地测试时,读取文件发现无论怎样都返回为NULL. >> select load_file('c:/xx/xx/xx/x.txt ...

  6. git如何上传文件夹

    git是不支持上传空文件夹的,文件夹里面必须有文件才可以 1.本地仓库上传文件夹到远程 在本地仓库新建一个文件夹,如果里面没有文件,那么$ git push origin master 不能将文件夹p ...

  7. centos 启动 elasticsearch 失败集

    环境: elasticsearch 6.5.2, java 连接失败 启动后当你 使用 curl http://localhost:9200 测试时,得到如下结果 Curl: (7) Failed c ...

  8. JQuery实现tab页

    用ul 和 div 配合实现tab 页 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="U ...

  9. 温故知新----封装(struct)

    上次提到class是最常见的封装,今天发现别人开发的SDK里面有大量的结构体struct 转载: 1. https://blog.csdn.net/a_forever_dream/article/de ...

  10. ISP-OB, pedestal 以及ISP概述

    网上的直接参考资料 1. https://zhuanlan.zhihu.com/p/36896537 2. https://blog.csdn.net/m0_38049850/article/deta ...