快速传送

手撸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. Java垃圾回收System.gc()的理解

    System.gc()无法保证GC一定执行 在默认情况下,通过System.gc()或者Runtime.getRuntime().gc()的调用,会显式触发Full GC,同时对老年代和新生代进行回收 ...

  2. pycharm2020.2破解版教程激活码支持Windows Linux Mac系统-中关村老大爷

    听说很多朋友想要PyCharm专业版2020.2的破解教程.现在来了,亲测破解成功.支持mac linux windows系统.本教程提供官方安装包.激活码和注册补丁. 本教程仅供学习和讨论,禁止商业 ...

  3. springboot之logback配置

    参考了https://blog.csdn.net/hxtxgfzs/article/details/79488163 Spring Boot默认情况下,当使用"Starters" ...

  4. java Synchronized集合

    在Collections存在相关"Synchronized"支持同步的集合, 在java1.0 也存在"Vector"; 为什么会选择放弃"Vecto ...

  5. Redis散列(Hash)的相关命令

    散列 就像一个减配的Redis 内部及其类似Java的Map 内容就是key:value结构 hash类型在面向对象编程的运用中及其适合,因为它可以直接保存编程语言中的实体类关系 增 hset hse ...

  6. 函数的arguments对象的使用和介绍

    arguments对象用于函数,当不知道传递了多少个实参,就可以使用arguments对象进行存储传递过来的实参(这时不需要写形参). arguments是一个内置对象,也是一个伪数组,我们可以按照数 ...

  7. java进阶(23)--List接口

    一.基本概念 1.有序可重复 2.有下标 3.包含ArraList.LinkedList.Vector   二.List中特有的方法 且常用 (以下军均为数组通用方法) 1.void add(int ...

  8. python3-day3

    一.函数基本语法及特性 重复用到的代码通过def封装起来,用到的时候直接调用函数名字:语法 1 def 函数名字(内容): 2 需要执行的动作 什么是函数: 函数一词来源于数学,但编程中的「函数」概念 ...

  9. Java知识系统回顾整理01基础06数组06二维数组

    一.一维数组和二维数组 这是一个一维数组, 里面的每一个元素,都是一个基本类型int int a[] =new int[]{1,2,3,4,5}; 这是一个二维数组,里面的每一个元素,都是一个一维数组 ...

  10. 如何使用微软提供的TCHAR.H头文件?

    转载:https://www.cnblogs.com/flyingspark/archive/2012/03/16/2399788.html 如何使用微软提供的TCHAR.H头文件? 如果你现在写的代 ...