草庐IT

通用ORM的设计与实现

流星轨迹 2023-04-17 原文

介绍

我们通用的ORM,基本模式都是想要脱离数据库的,几乎都在编程语言层面建立模型,由程序去与数据库打交道。虽然脱离了数据库的具体操作,但我们要建立各种模型文档,用代码去写表之间的关系等等操作,让初学者一时如坠云雾。我的想法是,将关系数据库拥有的完善设计工具之优势,来实现数据设计以提供结构信息,让json对象自动映射成为标准的SQL查询语句。只要我们理解了标准的SQL语言,我们就能够完成数据库查询操作。

相关项目

本项目依赖 本人的 另一个项目 Zjson,此项目提供简洁、方便、高效的Json库。该库使用方便,是一个单文件库,只需要下载并引入项目即可。具体信息请移步 gitee-Zjson 或 github-Zjson 。

项目名称说明

本人姓名拼音第一个字母z加上orm,即得本项目名称zorm,没有其它任何意义。我将编写一系列以z开头的相关项目,命名是个很麻烦的事,因此采用了这种简单粗暴的方式。

设计思路

ZORM 数据传递采用json来实现,使数据标准能从最前端到最后端达到和谐统一。此项目目标,不但在要C++中使用,还要作为动态链接库与node.js结合用使用,因此希望能像javascript一样,简洁方便的操作json。所以先行建立了zjson库,作为此项目的先行项目。设计了数据库通用操作接口,实现与底层实现数据库的分离。该接口提供了CURD标准访问,以及批量插入和事务操作,基本能满足平时百分之九十以上的数据库操作。项目基本目标,支持Sqlite3,Mysql,Postges三种关系数据库,同时支持windows、linux和macOS。

项目进度

现在已经实现了sqlit3与mysql的所有功能,postgres也做了技术准备。
我选择的技术实现方式,基本上是最底层高效的方式。sqlit3 - sqllit3.h(官方的标准c接口);mysql - c api (MySQL Connector C 6.1);postgres - pqxx 。

任务列表:

  •  Sqlite3 实现
    •  linux
    •  windows
    •  macos
  •  Mysql 实现
    •  linux
    •  windows
    •  macos
  •  Pstgre 实现
    •  linux
    •  windows
    •  macos

数据库通用接口

应用类直接操作这个通用接口,实现与底层实现数据库的分离。该接口提供了CURD标准访问,以及批量插入和事务操作,基本能满足平时百分之九十以上的数据库操作。

  class ZORM_API Idb
  {
  public:
      virtual Json select(string tablename, Json& params, vector<string> fields = vector<string>(), Json values = Json(JsonType::Array)) = 0;
      virtual Json create(string tablename, Json& params) = 0;
      virtual Json update(string tablename, Json& params) = 0;
      virtual Json remove(string tablename, Json& params) = 0;
      virtual Json querySql(string sql, Json params = Json(), Json values = Json(JsonType::Array), vector<string> fields = vector<string>()) = 0;
      virtual Json execSql(string sql, Json params = Json(), Json values = Json(JsonType::Array)) = 0;
      virtual Json insertBatch(string tablename, Json& elements, string constraint = "id") = 0;
      virtual Json transGo(Json& sqls, bool isAsync = false) = 0;
  };

实例构造

全局查询开关变量:

  • DbLogClose : sql 查询语句显示开关
  • parameterized : 是否使用参数化查询

Sqlite3:

    Json options;
    options.addSubitem("connString", "./db.db");    //数据库位置
    options.addSubitem("DbLogClose", false);        //显示查询语句
    options.addSubitem("parameterized", false);     //不使用参数化查询
    DbBase* db = new DbBase("sqlite3", options);

Mysql:

    Json options;
    options.addSubitem("db_host", "192.168.6.6");   //mysql服务IP
    options.addSubitem("db_port", 3306);            //端口
    options.addSubitem("db_name", "dbtest");        //数据库名称
    options.addSubitem("db_user", "root");          //登记用户名
    options.addSubitem("db_pass", "123456");        //密码
    options.addSubitem("db_char", "utf8mb4");       //连接字符设定[可选]
    options.addSubitem("db_conn", 5);               //连接池配置[可选],默认为2
    options.addSubitem("DbLogClose", true);         //不显示查询语句
    options.addSubitem("parameterized", true);      //使用参数化查询
    DbBase* db = new DbBase("mysql", options);

智能查询方式设计

查询保留字:page, size, sort, fuzzy, lks, ins, ors, count, sum, group

  • page, size, sort, 分页排序 在sqlit3与mysql中这比较好实现,limit来分页是很方便的,排序只需将参数直接拼接到order by后就好了。
    查询示例:

    Json p;
    p.addSubitem("page", 1);
    p.addSubitem("size", 10);
    p.addSubitem("size", "sort desc");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  ORDER BY age desc LIMIT 0,10
    
  • fuzzy, 模糊查询切换参数,不提供时为精确匹配 提供字段查询的精确匹配与模糊匹配的切换。

    Json p;
    p.addSubitem("username", "john");
    p.addSubitem("password", "123");
    p.addSubitem("fuzzy", 1);
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  WHERE username like '%john%'  and password like '%123%'
    
  • ins, lks, ors 这是最重要的三种查询方式,如何找出它们之间的共同点,减少冗余代码是关键。

    • ins, 数据库表单字段in查询,一字段对多个值,例:
      查询示例:
    Json p;
    p.addSubitem("ins", "age,11,22,36");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  WHERE age in ( 11,22,26 )
    
    • ors, 数据库表多字段精确查询,or连接,多个字段对多个值,例:
      查询示例:
    Json p;
    p.addSubitem("ors", "age,11,age,36");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  WHERE  ( age = 11  or age = 26 )
    
    • lks, 数据库表多字段模糊查询,or连接,多个字段对多个值,例: 查询示例:
    Json p;
    p.addSubitem("lks", "username,john,password,123");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  WHERE  ( username like '%john%'  or password like '%123%'  )
    
  • count, sum 这两个统计求和,处理方式也类似,查询时一般要配合group与fields使用。

    • count, 数据库查询函数count,行统计,例: 查询示例:
    Json p;
    p.addSubitem("count", "1,total");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT *,count(1) as total  FROM users
    
    • sum, 数据库查询函数sum,字段求和,例: 查询示例:
    Json p;
    p.addSubitem("sum", "age,ageSum");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT username,sum(age) as ageSum  FROM users
    
  • group, 数据库分组函数group,例:
    查询示例:

    Json p;
    p.addSubitem("group", "age");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  GROUP BY age
    

不等操作符查询支持

支持的不等操作符有:>, >=, <, <=, <>, =;逗号符为分隔符,一个字段支持一或二个操作。
特殊处:使用"="可以使某个字段跳过search影响,让模糊匹配与精确匹配同时出现在一个查询语句中

  • 一个字段一个操作,示例: 查询示例:
    Json p;
    p.addSubitem("age", ">,10");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  WHERE age> 10
    
  • 一个字段二个操作,示例: 查询示例:
    Json p;
    p.addSubitem("age", ">=,10,<=,33");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  WHERE age>= 10 and age<= 33
    
  • 使用"="去除字段的fuzzy影响,示例: 查询示例:
    Json p;
    p.addSubitem("age", "=,18");
    p.addSubitem("username", "john");
    p.addSubitem("fuzzy", "1");
    (new DbBase(...))->select("users", p);
    
    生成sql:   SELECT * FROM users  WHERE age= 18  and username like '%john%'
    

具体使用方法,请参看uint test。

单元测试

有完整功能的单元测试用例,请参见tests目录下的测试用例。

测试用例运行结果样例 

项目地址

https://gitee.com/zhoutk/zorm
或
https://github.com/zhoutk/zorm

运行方法

该项目在vs2019, gcc7.5, clang12.0下均编译运行正常。

git clone https://github.com/zhoutk/zorm
cd zorm
cmake -Bbuild .

---windows
cd build && cmake --build .

---linux & macos
cd build && make

run zorm or ctest

注在linux下需要先行安装mysql开发库, 并先手动建立数据库 dbtest。
在ubuntu下的命令是: apt install libmysqlclient-dev

相关项目

会有一系列项目出炉,网络服务相关,敬请期待...

gitee-Zjson github-Zjson

有关通用ORM的设计与实现的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  3. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  4. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  5. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  6. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  7. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  8. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  9. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  10. ruby - Arrays Sets 和 SortedSets 在 Ruby 中是如何实现的 - 2

    通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复

随机推荐