feat: 简化技术描述语言(2.8)

This commit is contained in:
dayjoy
2025-08-20 10:36:53 +08:00
parent 9d0ccd1372
commit 11eb3f3b37

View File

@@ -525,111 +525,118 @@ TOCO中判断使用方式的步骤
- 建议在Converter中扩展代码不建议修改结构定义文件。VO的**自定义字段**不直接派生自DTO一般对应取数逻辑代码。涉及数据获取、计算和拼装时批量处理性能最好自定义字段对应代码位置**必须**放在Converter的**Map**基础转换方法convertTo${VoName}Map中批量取数组装如UserVoConverter.convertToUserVoMap
#### **2.8 查询对象(WO)**
- **定义与用途:** 在TOCO中WO表达某个Entity为基本,通过外键关系不断关联多个Entity的数据结构。WO还隐式表达数据取数拼装,这种拼装符合外键关系. WO作为ReadPlan查询上下文使用,所以在创建ReadPlan前需先创建WO对象。理解一个ReadPlan语义的时候需要WO作为上下文。
如果对应的需求在返回DTO|VO的时候需要对DTO|VO的列表属性进行过滤,则需要根据对应的DTO|VO结构定义,扩展对应WO对象需要过滤字段名需要和DTO|VO字段名保持一致),例如:
- **定义与用途:** WO基于Entity通过外键关系关联多个Entity的数据结构。WO表达数据取数拼装逻辑,符合外键关系WO作为ReadPlan查询上下文创建ReadPlan前需先创建WO对象。理解ReadPlan语义需要WO作为上下文。
当返回DTO|VO时需要对列表属性进行过滤则根据DTO|VO结构定义扩展对应WO对象过滤字段名需DTO|VO字段名一致)。例如:
查询DTO
<code>
class MeetingDto {
```java
class MeetingDto {
String meetingId;
String meetingName;
List<MeetingAgenda> agendaList;
}
</code>
需求是需要根据会议名称查询会议列表,并且根据会议议程信息过滤部分议程,那在定义查询对象的时候就需要包含议程信息,并且扩展字段的名称要定义为**agendaList**
- **查询对象设计元素的表达**
- 以json格式表达json schema 定义如下
}
```
需求根据会议名称查询会议列表,根据议程信息过滤部分议程定义查询对象时需包含议程信息,扩展字段定义为**agendaList**
- **查询对象设计元素表达**
以json格式表达json schema如下
```json
{
"type": "object","description": "查询对象定义", "required": ["dtoOrVoId","name","fromEntity"],
"properties": {
"name": {"type": "string", "description": "查询对象名称,英语表达,单词之间下划线分割,长度补超过32字符"},
"uuid": {"type": "string", "description": "查询对象uuid, 在更新的时候必须传递(只有根节点必须传递),创建的时候不传"},
"dtoOrVoId":{"type":"string","description":"返回数据对象(VO或DTO)的uuid,创建的时候必须指定,更新的时候不传"},
"moduleName": {"type": "string", "description": "查询对象所属模块名称,在创建的时候必须传递"},
"name": {"type": "string", "description": "查询对象名称,英语表达,下划线分割,超过32字符"},
"uuid": {"type": "string", "description": "查询对象uuid,更新时必传(只有根节点),创建时不传"},
"dtoOrVoId":{"type":"string","description":"返回数据对象(VO或DTO)的uuid创建时必填,更新时不传"},
"moduleName": {"type": "string", "description": "查询对象所属模块名称,创建时必传"},
"fromEntity": {"type": "string", "description": "查询对象对应的实体"},
"expandList": {
"type": "array", "description": "正向扩展列表",
"items":
{
"items": {
"type": "object","description": "正向扩展定义","required": ["field","wo","fieldName"],
"properties": {
"field": {"type": "string", "description": "指定fromEntity扩展字段必须是fromEntity外键字段"},
"field": {"type": "string", "description": "fromEntity扩展字段必须是fromEntity外键字段"},
"wo": {"$ref": "#"},
"fieldName": {"type": "string", "description": "扩展出来的字段名称"}
"fieldName": {"type": "string", "description": "扩展字段名称"}
}
}
},
"reverseExpandList": {
"type": "array", "description": "反向扩展列表",
"items":
{
"items": {
"type": "object","description": "反向扩展定义","required": ["field","wo","fieldName"],
"properties": {
"field": {"type": "string", "description": "指定fromEntity扩展字段必须是fromEntity外键字段"},
"field": {"type": "string", "description": "fromEntity扩展字段必须是fromEntity外键字段"},
"wo": {"$ref": "#"},
"fieldName": {"type": "string", "description": "扩展出来的字段名称"}
"fieldName": {"type": "string", "description": "扩展字段名称"}
}
}
}
}
}
```
- **如何创建/生成:**
- **创建思路** 按照需要查询返回的DTO|VO的结构构建出同构的WO对象扩展和反向扩展的字段名保持一致然后根据查询需求和过滤需求对WO进行二次裁剪或和扩展
- **创建/生成方式:**
- **创建思路** 按查询返回的DTO|VO结构构建同构WO对象扩展和反向扩展字段名保持一致根据查询需求和过滤需求对WO二次裁剪或扩展
- 去掉过滤和查询都不需要的扩展
- 补全查询或字段过滤需要扩展
- **关键配置:** Wo中的字段分三种a.继承Entity字段,Entity的字段类型一样b.扩展字段含正向替换和反向注入字段类型为WO或List<WO>;
- **字段扩展方式:** TOCO定义了一个WO组装方法适用于WO通过外键关系替换/注入对应Entity信息对象化表达有外键关系的Entity信息。只要存在外键关系且满足以下条件即可扩展a.对于正向替换:当前实体存在指向其他实体的外键字段b.对于反向注入:其他实体存在指向当前实体的外键字段。
例如有两个Entity
<code>
MeetingRoom{ //会议室
- 补全查询或字段过滤需要扩展
- **关键配置:** WO字段分三种a.继承Entity字段类型与Entity相同b.扩展字段含正向替换和反向注入字段类型为WO或List<WO>
- **字段扩展方式:** WO通过外键关系替换/注入对应Entity信息对象化表达有外键关系的Entity信息。存在外键关系且满足条件即可扩展a.正向替换:当前实体指向其他实体的外键字段b.反向注入:其他实体指向当前实体的外键字段。
例如两个Entity
```java
MeetingRoom{ //会议室
Long id;// 会议室id,主键
String name;// 会议室名称
}
Meeting { //会议
}
Meeting { //会议
Long id;// 会议id,主键
Long roomid; //占用会议室id到MeetingRoom外键n:1关系
Long backupRoomid; //备用会议室id到MeetingRoom外键n:1关系
Long roomid; //占用会议室id到MeetingRoom外键n:1关系
Long backupRoomid; //备用会议室id到MeetingRoom外键n:1关系
String title; //会议标题
DateTime startTime; //会议开始时间
DateTime endTime; //会议结束时间
}
```
Meeting和MeetingRoom是n:1关系。多个会议占用同一个会议室。
组装对象以某Entity为根时首先拥有与该Entity相同数据结构通过"正向替换"、"反向注入"行为递归组装有外键关系的Entity信息。
**正向替换**:选定表,该表有到另一表的外键。选择需求相关的外键属性,将外键属性替换为另一表为根的组装对象。获取基于外键且包含另一表详细属性的数据。
例如需要会议和占用会议室时将Meeting表中roomid外键替换为以MeetingRoom为根的组装对象backupRoomid不替换
```
MeetingWithRoomWo {
Long id;// 会议id
MeetingRoomWo room { //正向替换会议用的会议室信息,以会议室为根的对象
Long id; //会议室ID
String name;// 会议室名称
}
Long backupRoomid; // 不变化
String title; //会议标题
DateTime startTime; //会议开始时间
DateTime endTime; //会议结束时间
}
```
**反向注入**:选定表,其他表到该表有外键,选择需求相关的外键属性在选定表中增加以另一表为根的组合对象(1:1关系时)或组合对象列表(n:1关系时)。
需求:"获取会议室和占用它的会议信息"选定MeetingRoom基于Meeting表存在roomid字段为到MeetingRoom的n:1关系外键。将List<MeetingBaseDto>反向注入到MeetingRoom中
```
MeetingRoomWithMeetingWo {
Long id;// 会议室id
String name;// 会议室名称
List<MeetingBaseWo> meetingList { //反向注入使用该会议室的会议信息,以会议为根的对象
Long id;// 会议id
String title; //会议标题
DateTime startTime; //会议开始时间
DateTime endTime; //会议结束时间
}
</code>
其中Meeting和MeetingRoom是n:1关系。即多个会议室会占用同一个会议室。
当组装对象以某Entity为根时那么首先它将拥有和该Entity一样的数据结构并将通过下面的“正向替换”“反向注入”的行为递归的将多个互相之间有外键关系的Entity的信息组装到该组装对象中。
定义“正向替换”这个行为,选定一个表,这张表存在到另外一张表的一个或多个外键。选择和需求相关的具体的外键属性,将该外键属性替换为另一张表为根的组装对象。这样就可以获取基于某些外键且包含另一张表更详细的属性数据
例如需要会议和其占用会议室时将Meeting表中的roomid外键替换为以MeetingRoom为根的组装对象而backupRoomid对应的候选会议室具体信息和本需求无关不做任何替换。如下
<code>
MeetingWithRoomWo {
Long id;// 会议id
MeetingRoomWo room { //正向替换该会议用的会议室信息,是一个以会议室为根的对象
Long id; //会议室ID
String name;// 会议室名称
}
Long backupRoomid; // 不做变化
String title; //会议标题
DateTime startTime //会议开始时间
DateTime endTime //会议结束时间
}
</code>
又例如需要会议和其候选会议室时将Meeting表中的backupRoomid进行正向替换。
又例如需要会议且即需要其占用会议室也需要候选会议室时将Meeting表中的roomidbackupRoomid都进行正向替换。
同时TOCO还定义了“反向注入”这个行为选定一个表如果有另外的表到前表有外键选择和需求相关的具体的外键属性在选定表中增加一个以另外表为根的组合对象(当外键关系是1:1时)或者组合对象的列表(当外键关系是n:1时)。需求是“获取会议室和占用它的会议信息”需要选定MeetingRoom那么基于另外的表Meeting中存在字段roomid为到MeetingRoom的n:1关系外键。可以将List<MeetingBaseDto>反向注入到MeetingRoom中最终生成一个以Meeting为根的组装对象生成
<code>
MeetingRoomWithMeetingWo {
Long id;// 会议室id
String name;// 会议室名称
List<MeetingBaseWo> meetingList { //反向注入的用该会议室的会议信息,是以会议为根的对象
Long id;// 会议id
String title; //会议标题
DateTime startTime //会议开始时间
DateTime endTime //会议结束时间
}
}
</code>
这种“正向替换”和“反向注入”可以按需递归调用去将多个互相之间有外键关系的对象组装成最终对象。例如还有另外一张表MeetingAgenda到Meeting有n:1的外键,那么如果我要去组装以Meeting开始包含MeetingRoom, MeetingAgenda的查询对象首先发现MeetingRoom是可以正向扩展到Meeting的并且可以反向注入MeetingAgenda
- meeting_with_room_and_agenda_wo
<code>
}
```
"正向替换"和"反向注入"可按需递归调用,组装多个外键关系的对象。例如MeetingAgenda到Meeting有n:1外键组装以Meeting开始包含MeetingRoom、MeetingAgenda的查询对象MeetingRoom可正向扩展到Meeting可反向注入MeetingAgenda
meeting_with_room_and_agenda_wo示例
```json
{
"wo": {
"uuid": null,
@@ -661,7 +668,8 @@ TOCO中判断使用方式的步骤
]
}
}
</code>
```
#### **2.9 读方案 (ReadPlan)**
- **定义与用途:** 在TOCO中针对DTO和VO读方案描述了如何基于查询对象从数据库获取DTO和VO列表数据主要提供了三个能力
- 根据查询条件返回符合条件的DTO或VO的id列表
@@ -954,11 +962,13 @@ TOCO中判断使用方式的步骤
* 根据用户名称查询用户列表返回UserDTO则生成UserNameQto、UserNameQtoService、UserNameQtoDao、UserNameQueryService; UserNameQueryService调用UserNameQtoServiceUserNameQtoService调用UserNameQtoDao
- **修改建议:**
- 如果有对结果的数据二次处理建议在QueryService和QueryExecutor中进行代码扩展不建议修改QTO文件
#### **2.10 查询传输对象(QTO)**
- **定义与用途:** 在TOCO中QTO为读方案的查询参数结构每个读方案会对应一个QTO读方案调用方按照QTO的结构向读方案生成的RPC方法传入需要查询的实体字段值完成对数据库的查询
- **如何创建/生成:** 在创建读方案后TOCO会自动生成QTO作为该读方案传入的查询参数结构无需单独创建
- **关键配置:** 名称(${ReadPlanNameQto},驼峰展示),查询字段列表(如idIsnameLike, schoolNameLike等)
- **与API的关系:** QTO通常可作为API的参数API接收到参数后可直接透传给内部的RPC进行调用注意QTO只用作读操作的参数**禁止用作写参数结构**
#### **2.11 写方案 (WritePlan单聚合操作)**
- **定义与用途:** TOCO针对写场景定义了一种写方案所有对数据库的写操作都只能通过写方案实现一个写方案只可以变更一个聚合的数据无法同时操作多个聚合!。写方案包含了对数据库表的写操作。每个写方案只能操作一个聚合内部的表同时对一个聚合内表的操作尽量合并至一个写方案中根据复用性、内聚性等方面具体情况具体分析。注意写方案可以一次操作聚合内的多张表如location和storey是同一个聚合并且location和storey是**1:N**关系location是父对象聚合根storey是子对象那么我们可以创建一个写方案同时更新单个聚合根location中的信息以及操作其下的子表storey**列表**信息如新增、删除、修改storey等也可以创建一个写方案单独更新单个子表storey对象信息。
- **关键配置:** 名称(小写字母+下划线不要以write_plan结尾,全局唯一)操作的聚合聚合内的实体和字段对每个实体的操作类型CREATE创建**单个**实体UPDATE(更新**单个**实体), DELETE(删除**单个**实体), CREATE_ON_DUPLICATE_UPDATE(创建或者更新**单个**实体),FULL_MERGE( 批量更新**列表**数据根据传入的列表数据一条一条执行CREATE_ON_DUPLICATE_UPDATE的操作并且删除掉老的列表中不在传入列表数据中的部分), PARTIAL_MERGE(批量更新**列表**数据,根据传入的列表数据,一条一条执行)
@@ -1385,12 +1395,15 @@ TOCO中判断使用方式的步骤
- **例子:**
- 用户登录在UserFlowService中生成一个函数invokeLoginFlow该函数通过流程框架根据流程定义调用LoginNodeLoginNode中封装了用户登录的逻辑LoginFlowContext中封装了用户登录的参数和结果。
- **修改建议:** 不修改 service 中的函数, 不修改FlowConfig, 可以修改FlowContext, 添加/修改出入参数, 修改FlowNode中的具体业务逻辑。
#### **2.16 自定义查询**
#### **2.12 自定义查询**
- 在读方案无法满足需求的情况下,可以使用自定义查询
- 自定查询使用复杂的sql实现业务功能
- 自定义查询的数据访问层使用MyBatis、MyBatisPlus实现
- 自定查询的时候框架不自动生成任何代码(需要模型编写全部代码)
- 各层的代码位置严格遵守章节:**3.2 项目结构与导航**必须有mapper层、service层、必须有DO对象、必须有DTO对象如果是API返回数据必须有VO对象
### **3 生成代码产物补充说明**
- **3.1 支持的语言/框架**
Java、SpringBoot、MyBatis-plus(读)、Hibernate(写)