Replies: 1 comment
-
不考虑指针形态的组合,理由也是非常简单:
|
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
需求分析
目前来说,我们仅仅支持最为简单的模型定义。但是在大多数场景下,用户会考虑使用组合来定义模型。例如常见的是公司有规范,所有的数据库表都必须有创建时间和更新时间。在这种情况下,最好的解决方案就是大家都组合一个公共的结构体,例如:
在这种情况下,我们认为
User
对应的表含有三个列:id
,create_time
和update_time
。场景分析
除了前面提到的这种最简单的组合形式以外,用户可能定义一些比较奇怪的组合形式。
指针组合
目前我们不需要支持 UserV1 这种形态,即不支持使用指针的组合。目前想象不到在 ORM 场景中,有什么是必须要使用这种形态来解决的。
多重组合
这种虽然罕见,但是可以考虑支持。
嵌套组合
即组合套组合。
嵌套组合在复杂的企业级应用中可能会出现,所以可以考虑支持这种形态。那么结合前面多重组合,那么这种形态也是可以的:
字段冲突
在简单的模型定义里面,是不存在字段冲突的情况的,因为编译期会直接报错。但是在引入了组合之后,那么字段冲突就变可能了。冲突可能是内部结构体字段和外部结构体字段冲突,也可能是多重嵌套不同内部结构体之间的字段冲突。例如:
或者:
在 eorm 中,组合被认为是同一张表,而同一张表是不允许出现重复列的。我们的选择是,如果碰到冲突列,我们会报错。等到将来综合用户反馈,再进一步考虑要不要放松这个限制。
忽略组合
某些时候用户希望忽略掉组合。例如说:
组合与普通字段的区别
另外还有一点需要澄清,即组合和普通字段在模型定义上的不同语义:
关键在于,在使用组合的情况下,我们认为它们是同一张表;而定义成 UserV3 这种普通字段,我们认为它更加接近于关联关系,即一对多,多对一等。
功能需求
从前面的场景分析可以总结下来,我们需要做到的是:
同样地,组合的内部结构体字段也可以使用
eorm
标签,用于定义列的别名等。非功能需求
在引入组合之后,影响最大的就是性能,而且使用组合的性能必然比不使用组合的性能差。因为组合难免会引入递归计算之类的问题。很显然,这样会比普通的结构体消耗更多的 CPU 资源和内存资源。
行业方案
简单来说,支持组合应该算是 ORM 里面的标准。GORM,Beego ORM,ENT,Vitess 都支持组合,虽然他们从程度上来说各不相同。因为我们在场景分析里面已经做出了决定究竟要支持什么样的组合,所以这里就不必深入探究它们对组合的支持程度。
设计
支持组合主要影响的是
这两个部分可以看做是 eorm 的核心模块,因为相应的,CRUD 等各种查询也会间接收到影响。
详细设计
模型元数据解析
目前我们已经有了一个接口和一个实现:
那么修改就局限于在它的
Register
方法。这个Register
无可避免要使用递归来解析元数据:要点是:
Register
不再直接解析字段,而是依赖于parseField
进行解析parseField
会遍历字段,如果一个字段是组合,那么就递归解析parseField
在递归解析组合的时候,会检测字段有没有冲突Value 读字段
目前我们设计的
Value
接口,只含有一个方法:并且只有一个基于反射的实现
reflectValue
。所以在支持组合之后要考虑如何读取到组合的字段,例如在模型定义为:如果发起调用
val.Field("CreateTime")
,那么应该返回BaseEntity.CreateTime
的值。解决方案是引入祖先概念。在
ColumnMeta
里面新加一个字段:那么
reflecValue
的取值逻辑就变成:相应地,要在前面的
parseFields
里面加上相应的计算Ancestors
的逻辑。IgnoreFieldsOption
这个方法也要考虑支持忽略组合:
测试
单元测试
单元测试要覆盖功能需求里面的场景:
同时要考虑这些场景混合在一起:
集成测试
N/A。
基准测试
要对
Register
方法和Field
进行基准测试,要考虑三种情况:模糊测试
需要对
Field
进行模糊测试。同样需要考虑三种情况:Beta Was this translation helpful? Give feedback.
All reactions