前言
golangORM
ORMORM

然后我总结了他们呢的一些共性和差异点,于是形成了本文的主要内容。

code firstdatabase first
javac#phppythongo

如果你需要做技术选型,或者做技术研究,或者类似于我做框架开发,或者单纯地了解各语言的差异,或者就是想吹个牛,建议保存或收藏。如果本文所涉及到的内容有任何不正确,欢迎批评指正。

温馨提示,本文会有一些戏谑或者调侃成分,并非对某些语言或者语言的使用者有任何歧视意见。

如果对你造成了某些伤害,请多包涵。

什么是SQL编写难题

如果你是做web开发,那么必然需要保存数据到数据库,这个时候你必须熟悉使用sql语句来读写数据库。

sql本身不难,命令也就那几个,关键字也不算多,但是为什么编写sql会成为难题呢?

比如下面的sql

sql

但是,如果你需要写下面的sql呢?

sql

再稍微复杂点,如果是下面的sql?

sql

如上面的sql所示,SQL编写难题在于以下几方面。

要保证字段正确

应该有的字段不能少,不应该有的字段不能多。

mobilemobike

并且项目越大,表越多,字段越多,这种拼写错误发生的可能性越大。以至于可以肯定的说,100%的可能性会出现。

要特别注意sql语法

fromform
sql

编辑器不会有sql的语法提示

常见的编码用的软件,对于sql相关的代码,不会有语法提示,也不会有表名提示,字段名提示。

最终的代码质量如何全凭你的眼力,经验,能力。

很显然,既然存在该难题,那么哪个ORM能解决该难题,就应该算得上好,如果不能解决,则不能称之为好。

什么是code first 和 database first

这俩概念并不是新概念,但是我估计大多数开发者并不熟悉。

所谓 code first, 相近的词是 model fist, 意思是模型优先,指的是在设计和开发系统时,优先和重点做的工作是设计业务模型,然后根据业务模型去创建数据库。

所谓 database first,意思是数据库优先,指的是在设计和开发系统时,优先和重点做的工作是创建数据库结构,然后去实现业务。

这里我提到了几个词语,可能在不同的语言里叫法不一样,可能不同的人的叫法也不一样,为了下述方便,我们举例子来说。

code first 例子

假设我是一个对电商系统完全不懂的小白,手头上也没有如何设计电商系统的资料,我和我的伙伴只是模糊地知道电商系统主要业务就是处理订单。

然后我大概会知道这个订单,主要的信息包括哪个用户下单,什么时间下单,有哪几种商品,数量分别是多少,根据这些已有的信息,我可以设计出来业务模型如下

很简单,对吧,这个模型很匹配我目前对系统的认知。接下来会做各种业务逻辑,最后要做的是将订单模型的数据保存到数据库。但是在保存数据到数据库的时候,就有一些考虑了。

OrderModel

但是我是电商小白,不是数据库小白啊,这样存储的话,肯定不利于统计订单商品的。

OrderModel

然后将 orderDetail 的信息进行再次分解,放到另一个类里

orderorder_detailOrderEntityOrderDetailEntity
OrderModelorderorder_detail

这就是 code first ,注意这个过程的关键点,我优先考虑的是模型和业务实现,后面将业务模型数据进行分解和保存是次要的,非优先的。

database first 例子

假设我是一个对电商系统非常熟悉的老鸟,之前做过很多电商系统,那么我在做新的电商系统的时候,就完全可以先设计数据库。

order
order_detail
OrderEntityOrderDetailEntityOrderModel

这就是 database first ,注意这个过程的关键点,我优先考虑的是数据库结构和数据表结构。

两种方式对比

OrderModel
orderorder_detail
orderorder_detail
orderorder_detail

至此,我们可以有以下粗浅的判断:

对于新项目,不熟悉的业务,code first 模式更适合一些

对于老项目,熟悉的业务,database first 模式更合适一些

如果两种模式都可以的话,优先使用 code first 模式,便于理解业务,把控项目

如果哪个ORM支持 code first , 我们可以稍稍认为它更好一些

Java体系的orm

Java语言是web开发领域处于领先地位,这一点无可置疑。它的优点很明显,但是缺点也不是没有。

国内应用比较广泛的orm是Mybatis,以及衍生品Mybatis-plus等

实际上Mybatis团队还出了另外一款产品,MyBatis Dynamic SQL,国内我见用的不多,讨论都较少。英文还可以的同学,可以看下面的文档。

另外还有 jOOQ, 实际上跟 MyBatis Dynamic SQL 非常类似,有兴趣的可以去翻翻

下面,我们举一些例子,来对比一下他们的基本操作

Java体系的Mybatis

单就orm这一块,国内用的最多的应该是Mybatis,说到它的使用体验吧,那简直是一言难尽。

xmlxml
xmlsql
xml
xmlSQL编写难题

Java体系的Mybatis-plus

xml
xmlsql

但是,请你注意我的用词,是减少了一些。

对于连表操作,嵌套查询等涉及到多表操作的事情,它就不行了,为啥不行,因为根本就不支持啊。

xmlSQL编写难题

Java体系的Mybatis3 Dynamic Sql

值得一提的是Mybatis3 Dynamic Sql,翻译一下就是动态sql。还是刚才说的国内我见用的不多,讨论都较少,但是评价看上去挺好。

简单来说,可以根据不同条件拼接出sql语句。不同于上面的Mybatis,这些sql语句是程序运行时生成的,而不是提前写好的,或者定义好的。

它的使用流程是,先在数据库里定义好数据表,然后创建模型文件,让然后通过命令行工具,将每一个表生成如下的支持文件

可以看出,这里的主要功能能是将表内的字段,与java项目里的类里面的属性,做了一一映射。

接下来你在开发的时候,就不用关心表名,以及字段名了,直接使用刚才生成的类,以及类下面的那些属性。具体如下

如上面的代码,好处有以下四点

SQL编写难题
PersonDynamicSqlSupport
database first
C#体系的orm

C# 在工业领域,游戏领域用的多一些,在web领域少一些。

它也有自己的orm,名字叫 Entity Framework Core, 一直都是微软公司在维护。

下面是一个典型的联表查询

这句代码的主要作用是,将数据库里的Posts表,与Post_Metas表做内联操作,然后取出Post.ID等于1的数据

这里出现的Post,以及Meta都是提前定义好的模型,也就是类。 Post.ID 是 Post 的一个属性,也是提前定义好的。

SQL编写难题code first

对比java的Mybatis以及Mybatis3 Dynamic Sql来说,你可以脑补一下下面的场景

PHP体系的orm
laravelsymfony

PHP体系的laravel

laravel

这里没有使用模型(就算使用了也差不多),代码里出现的 users 就是数据库表的名字, name 是 users 表里的字段名,他们是被直接写入代码的

SQL编写难题
database first

PHP体系的symfony

这个框架历史也比较悠久了,它使用了 Doctrine 找个类库作为orm

使用它之前,也需要先定义模型,然后生成支持文件,然后建表,但是在实际使用的时候,还是和laravel一样,表名,字段名都需要硬编码

SQL编写难题
code first
python体系的orm

在python领域,有一个非常著名的框架,叫django, 另外一个比较出名的叫flask, 前者追求大而全,后者追求小而精

python体系的django

django推荐的开发方法,也是先建模型,但是在查询的时候,这建立的模型,基本上毫无用处

如上连表查询的代码,values('title','publish__name') 这里面写的全都是字段名,硬编码进去,进而产生sql语句,查询出结果

SQL编写难题
code first

python体系的flask

flask本身没有orm,一般搭配 sqlalchemy 使用

使用 sqlalchemy 的时候,一般也是先建模型,然后查询的时候,可以直接使用模型的属性,而无须硬编码

如上 Article.id 即是 Article 模型下的 id 属性

SQL编写难题
code first
go体系的orm

在go体系,orm比较多,属于百花齐放的形态,比如国内用的多得gorm以及gorm gen,国外比较多的ent, 当然还有我自己写的 arom

go体系下的gorm

使用gorm,一般的流程是你先建立模型,然后使用类似如下的代码进行操作

这是一个嵌套查询,虽然定义了模型,但是查询的时候并没有使用模型的属性,而是输入硬编码

SQL编写难题
code first

go体系下的gorm gen

gorm gen 是 gorm 团队开发的另一款产品,和mybaits下的Mybatis3 Dynamic Sql比较像

它的流程是 先创建数据表,然后使用工具生成结构体(类)和支持代码, 然后再使用生成的结构体

它生成的比较关键的代码如下

注意看,其中大多数代码的作用是啥?不意外,就是将结构体的属性与表字段做映射关系

_user.Name 对应 name

_user.Age 对应 age

如此,跟mybaits下的Mybatis3 Dynamic Sql的思路非常一致

典型查询代码如下

这是一个分组查询,定义了模型,也使用了模型的属性。

但是呢,它需要使用工具生成额外的支持代码,并且需要先定义数据表

SQL编写难题
database first

go体系下的ent

ent 是 facebook公司开发的Orm产品,与 gorm gen 有相通,也有不同

相同点在于,都是利用工具生成实体与数据表字段的映射关系

不同点在于gorm gen先有表和字段,然后生成实体

ent是没有表和字段,你自己手动配置,配置完了一起生成实体和建表

接下来,看一眼ent生成的映射关系

有了映射关系,使用起来就比较简单了

注意,这里没有硬编码

它需要使用工具生成额外的支持代码,并且需要先配置表结构

SQL编写难题
database first

go体系下的aorm

aorm 是我自己开发的orm库,吸取了ef core 的一些优点,比较核心的步骤如下

和大多数orm一样,需要先建立模型,比如

然后实例化它,并且保存起来

然后即可使用

SQL编写难题
code first
总结

本文,我们提出了两个衡量orm功能的原则,并且对比了几大主流后端语言的orm,汇总列表如下

单就从这张表来说,不考虑其他条件,在做orm技术选型时,

SQL编写难题
SQL编写难题code first
SQL编写难题
SQL编写难题code first
SQL编写难题code first

好了,文章写两天了,终于写完了。

如果我有说的不合适,或者不对的地方,请在下面狠狠的批评我。

参考文档