博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AppBoxFuture(八): 另类的ORM实现
阅读量:5292 次
发布时间:2019-06-14

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

  通常的ORM实现基于配置或注释,由反射或Emit生成相应的Sql语句,然后将Sql发送给数据库解析Sql字符串生成AST再交给优化器处理后执行,返回的数据再经由反射或Emit转换为相应的实体实例。作者认为上述方式主要存在以下两个问题:

  1. 实体类代码是硬编码的,如果实体类定义变更必须重新编译应用再部署,不利于实现运行时动态变更实体定义;
  2. CRUD操作转换为Sql的实现复杂,且需要针对不同的数据库做适配优化。

  由于作者追求极致简单的系统架构以及丝般顺滑的开发体验,所以作者采用了另类的方式在框架内实现了ORM,之于另类在什么地方我们先通过一些简单示例后再来说明一下实现原理。

一、CRUD操作

  还是用系统自带的Emploee模型作为示例,在IDE新建服务模型添加以下代码保存发布后可通过主菜单->Service->Invoke运行测试:

4928-20190531080825903-768462446.png

//事务新建两条记录var emp1 = new Entities.Emploee();emp1.Name = "Rick";emp1.Account = "rick@appbox.dev";emp1.Birthday = new DateTime(1977, 3, 16);var emp2 = new Entities.Emploee();emp2.Name = "Johne";emp2.Account = "johne@appbox.dev"emp2.Birthday = new DateTime(1979, 1, 2);var txn = await Transaction.BeginAsync();try {    await EntityStore.SaveAsync(emp1, txn);    await EntityStore.SaveAsync(emp2, txn);    await txn.CommitAsync();} catch (Exception ex) {    txn.Rollback();}//查询记录var q = new TableScan
();q.Filter(t => t.Name == "Rick");var emps = await q.ToListAsync();//更新记录emps[0].Name = "Rick Lu";await EntityStore.SaveAsync(emps[0]);//删除记录await EntityStore.DeleteAsync(emps[0]);

  以上只是已实现的一些Api示例,复杂的如根据索引查询、聚合查询等Api正在设计开发中。

二、实现原理

设计时:

  这部分实现重度依赖Roslyn功能,服务端在开发人员登录至IDE后会通过Roslyn生成虚拟项目。

4928-20190531080841770-1695482139.jpg

  • 实体模型保存时服务端生成虚拟的实体类代码,并加入虚拟项目内;
  • 服务模型保存时服务端生成虚拟的服务类代码,并加入虚拟项目内;发布时服务端的编译引擎解析虚拟的服务代码,然后转换为运行时服务代码,再通过Roslyn编译为动态服务组件。其中虚拟代码转换为运行时代码的过程主要是:
  1. 将实体属性取赋值操作(eg: entity.Name = "aa" 或 var temp = entity.Name)转换为针对运行时Entity类的GetXXX()及SetXXX()操作。这里需要注意的是运行时只存在一个Entity类(类似于KVO通过字典表保存属性值)
  2. 将查询条件转换为可序列化的表达式,这样存储引擎执行查询命令时可委托clr emit生成过滤指令,存储引擎在扫描时直接使用过滤指令计算满足条件的记录。

运行时:

  这部分实现参考以下流程图,需要注意的是存储引擎是基于RocksDB的,实体数据转换为KV数据(如Key=Id, Value=[字段标识:字段值;字段标识:字段值]),这样转换过程就不需要使用反射或Emit。

4928-20190531080851078-1134429586.jpg

三、性能测试

  作者做了简单的性能测试(单节点I74C8G虚拟机):

  • 并发插入不带索引不带外键的简单实体约28000tps;
  • 通过惟一索引查询约80000qps;
  • 带条件扫描少量记录约35000qps。

四、查询限制

  • 存储引擎不支持join,可通过分别查询出数据后利用Linq做join操作;
  • 存储引擎暂只支持根据Entity.Id或指定索引查询排序,不支持自定义排序。

五、本篇小结

  本篇主要介绍了框架集成的ORM的另类实现,上的运行时已经更新可测试。如果您有问题或Bug报告,请留言或在提交Issue。

转载于:https://www.cnblogs.com/BaiCai/p/10953149.html

你可能感兴趣的文章
线性表可用顺序表或链表存储的优缺点
查看>>
在现有的mysql主从基础上,搭建mycat实现数据的读写分离
查看>>
opencv安装配置
查看>>
JAVA-初步认识-第六章-面向对象(举例)
查看>>
js合并数组
查看>>
cNoteSetCursor_命令窗口光标设置
查看>>
[Flex] flex手机项目如何限制横竖屏?只允许横屏?
查看>>
tensorflow的graph和session
查看>>
Benelux Algorithm Programming Contest 2014 Final(第二场)
查看>>
随机变量的期望为什么把不是自己密度函数当成自己的权重来求期望呢?
查看>>
6-1 并行程序模拟 uva210
查看>>
JavaScript动画打开半透明提示层
查看>>
Mybatis生成resulteMap时的注意事项
查看>>
jquery-jqzoom 插件 用例
查看>>
javascript知识点记录01
查看>>
javascript事件代理
查看>>
es6 新增特性
查看>>
1007. Maximum Subsequence Sum (25)
查看>>
《算法》C++代码 快速排序
查看>>
iframe的父子层跨域 用了百度的postMessage()方法
查看>>