快速传送

手撸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. php第二天-函数的用法及封装,变量范围,匿名函数,递归函数

    1.函数 <?php function test($info){ return $info; } echo test("hello") ?> 输出hello 2.函数实 ...

  2. Fowsniff靶机

    Fowsniff靶机 主机探测+端口扫描. 扫目录没扫到什么,看一下页面源代码. 网站主页告诉我们这个站现在不提供服务了,并且因为收到了安全威胁,攻击者将他们管理员信息发布到了社交媒体上. 大家要科学 ...

  3. CBC字节翻转攻击

    iscc2018线上赛开始两周多了,学到了很多,写几篇文章总结一下遇到的知识点,做一个归纳,方便以后查找. web300-----CBC字节翻转攻击 cbc是AES加密的cbc模式 即密码分组链模式: ...

  4. 用Docker swarm快速部署Nebula Graph集群

    用Docker swarm快速部署Nebula Graph集群 一.前言 本文介绍如何使用 Docker Swarm 来部署 Nebula Graph 集群. 二.nebula集群搭建 2.1 环境准 ...

  5. ser 序列化的使用

    2.序列化(serializers.Serializer) 1)序列化(正向查找) from rest_framework import serializers from users.models i ...

  6. nginx 1.12安装

    准备工作 使用root用户安装. 到nginx官网下载Linux源码或者执行:wget http://nginx.org/download/nginx-1.12.2.tar.gz. 到pcre站点下载 ...

  7. Python-装饰器中保留被装饰函数元数据

     函数的元数据包括哪些呢? 1. 函数名 .__name__ 2. 函数注释 .__doc__ ... 那,如何保留被装饰函数元数据,通过wraps装饰器保留被装饰函数的元数据 import time ...

  8. 决策树防止过拟合(预剪枝(Pre-Pruning))

    预剪枝(Pre-Pruning):预剪枝就是在构造决策树的过程中,先对每个结点在划分前进行估计,若果当前结点的划分不能带来决策树模型泛华性能的提升,则不对当前结点进行划分并且将当前结点标记为叶结点.

  9. mysql-10-union

    #进阶10:联合查询 /* union联合 将多条查询语句的结果合并成一个结果 语法: 查询1 union 查询2 union 查询3 ... 应用场景:要查询的结果来自于多个表,且多个表没有直接的连 ...

  10. Java知识系统回顾整理01基础04操作符03逻辑运算符

    一.长路与 和 短路与 无论长路与还是短路与 两边的运算单元都是布尔值 都为真时,才为真 任意为假,就为假 区别 长路与 两侧,都会被运算 短路与 只要第一个是false,第二个就不进行运算了 pub ...