一种巧妙的对象映射关系设计–JSON-ORM

70次阅读

共计 3351 个字符,预计需要花费 9 分钟才能阅读完成。

项目介绍
这是标准数据库封装的上半部分,智能查询(JSON-ORM)的实现。完整代码:https://github.com/zhoutk/gels
设计思路
我们通用的 ORM,基本模式都是想要脱离数据库的,几乎都在编程语言层面建立模型,由程序去与数据库打交道。虽然脱离了数据库的具体操作,但我们要建立各种模型文档,用代码去写表之间的关系等等操作,让初学者一时如坠云雾。我的想法是,将关系数据库拥有的完善设计工具之优势与微服务结合起来,数据设计提供结构信息;前端送到后端的 json 对象自动映射成为标准的 SQL 查询语句。只要我们理解了标准的 SQL 语言,我们就能够完成数据库查询操作。我的这种 ORM 方式,服务端不需要写一行代码,只需完成关系数据库的设计,就能为前端提供标准服务接口。并且遵循一套统一的接口(已经实践检验,满足百分之九九的查询需求)来实现数据库封装,达到业务层可以随意切换数据库的目的。
数据库查询操作接口。
export default interface IDao {
select(tablename: string, params: object, fields?: Array<string>): Promise<any>; // 自动生成 sql 语句
execSql(sql: string, values: Array<any>, params: object, fields?: Array<string>): Promise<any>; // 执行手动 sql 语句
}
智能查询(JSON-ORM)
查询保留字:fields, page, size, sort, search, lks, ins, ors, count, sum, group

fields, 定义查询结果字段,支持数组和逗号分隔字符串两种形式由前端来确定返回的数据库字段信息,这样后端的设计可以适用面更广泛,而不会造成网络带宽的浪费。在 KOA2 的框架下,GET 请求要支持输入数组,只能把同一个 key 多次输入,如:age=11&age=22。这样很不方便,我实现了一个参数转换函数,针对数组提供多种输入形式。arryParse
arryParse(arr): Array<any>|null {// 返回值为数据或空值
try {
if (Array.isArray(arr) || G.L.isNull(arr)) {// 如果输入是数组或空,直接返回
return arr
} else if (typeof arr === ‘string’) {// 若是字符串
if (arr.startsWith(‘[‘)) {// 数组的字符串形式,进行转换
arr = JSON.parse(arr)
} else {
// 逗号拼接的字符串,mysql 的驱动同时支持参数以字符串形式或数组形式提供,
// 所以这里可以不加判断,直接用 split 函数将字符串转化为数组
arr = arr.split(‘,’)
}
}
} catch (err) {
arr = null // 数组的字符串形式转换失败,刘明输入参数是错误的
}
return arr
}
查询示例:
请求 URL:/rs/users?username=white&age=22&fields=[“username”,”age”]
生成 sql:SELECT username,age FROM users WHERE username = ? and age = ?

page, size, sort, 分页排序在 mysql 中这比较好实现,limit 来分页是很方便的,排序只需将参数直接拼接到 order by 后就好了。查询示例:
请求 URL:/rs/users?page=1&size=10&sort=age desc
生成 sql:SELECT * FROM users ORDER BY age desc LIMIT 0,10

search, 模糊查询切换参数,不提供时为精确匹配提供字段查询的精确匹配与模糊匹配的切换,实现过程中,注意参数化送入参数时,like 匹配,是要在参数两边加 %,而不是在占位符两边加 %。另外,同一个字段匹配两次模糊查询,需要特别处理,我提供了一种巧妙的方法:
value = pool.escape(value).replace(/\’, \’/g, “%’ and ” + key + ” like ‘%”) // 将值用 escape 编码,数组将转化为逗号连接的字符串,用正则全局替换,变成 and 连接
value = value.substring(1, value.length – 1) // 去掉两头多余的引号
where += key + ” like ‘%” + value + “%'” // 补齐条件查询语句,这种方式,比用循环处理来得快捷,它统一了数组与其它形式的处理方式
查询示例
请求 URL:/rs/users?username=i&password=1&search

ins, lks, ors 这是最重要的三种查询方式,如何找出它们之间的共同点,减少冗余代码是关键。

ins, 数据库表单字段 in 查询,一字段对多个值,例:查询示例:
请求 URL:/rs/users?ins=[“age”,11,22,26]
生成 sql:SELECT * FROM users WHERE age in (?)

ors, 数据库表多字段精确查询,or 连接,多个字段对多个值,支持 null 值查询,例:查询示例:
请求 URL:/rs/users?ors=[“age”,1,”age”,22,”password”,null]
生成 sql:SELECT * FROM users WHERE (age = ? or age = ? or password is null)

lks, 数据库表多字段模糊查询,or 连接,多个字段对多个值,支持 null 值查询,例:查询示例:
请求 URL:/rs/users?lks=[“username”,”i”,”password”,null]
生成 sql:SELECT * FROM users WHERE (username like ? or password is null)

count, sum 这两个统计求和,处理方式也类似,查询时一般要配合 group 与 fields 使用。

count, 数据库查询函数 count,行统计,例:查询示例:
请求 URL:/rs/users?count=[“1″,”total”]&fields=[“username”]
生成 sql:SELECT username,count(1) as total FROM users

sum, 数据库查询函数 sum,字段求和,例:查询示例:
请求 URL:/rs/users?sum=[“age”,”ageSum”]&fields=[“username”]

group, 数据库分组函数 group,例:查询示例:
请求 URL:/rs/users?group=age&count=[“*”,”total”]&fields=[“age”]
生成 sql:SELECT age,count(*) as total FROM users GROUP BY age

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

一个字段一个操作,示例:查询示例:
请求 URL:/rs/users?age=>,10
生成 sql:SELECT * FROM users WHERE age> ?

一个字段二个操作,示例:查询示例:
请求 URL:/rs/users?age=>,10,<=,35
生成 sql:SELECT * FROM users WHERE age> ? and age<= ?

使用 ”=” 去除字段的 search 影响,示例:查询示例:
请求 URL:/rs/users?age==,22&username=i&search
生成 sql:SELECT * FROM users WHERE age= ? and username like ?

相关视频课程
运用 typescript 进行 node.js 后端开发精要 nodejs 实战之智能微服务快速开发框架 JSON-ORM(对象关系映射)设计与实现
资源地址
凝胶(gels)项目:https://github.com/zhoutk/gels 视频讲座资料:https://github.com/zhoutk/sifou 个人博客:https://github.com/zhoutk/blog

正文完
 0