在上一篇文章(Prisma不能优雅的支持DTO,试试Vona ORM吧)中,我们基于静态关系实现了目录树的关联查询,并且动态推断生成了DTO(用于Swagger元数据)。在这篇文章我们探讨动态关系的用法。
什么是动态关系
那么,什么是动态关系呢?在大型业务系统中,我们会创建大量数据模型,这些数据模型之间的关联众多,我们不可能将所有关联通过静态关系的机制事先声明出来。特别是当存在大量业务模块,这些数据模型散落在不同的业务模块中,那么通过静态关系事先声明所有的关联关系也变得不太现实。比如,Prisma就只支持静态关系。如果事先没有定义静态关系,在实际代码中,我们就需要提供一种使用动态关系的机制,让我们的查询、类型推断、DTO推断等能力得以正常使用。
准备数据模型
在上一篇文章中,我们已经介绍了如何创建Entity和Model,这里不再赘述。而是直接把Order和Customer的Entity和Model罗列出来,然后演示动态关系的用法
Entity
1. Order
- @Entity()
- export class EntityOrder extends EntityBase {
- @Api.field(v.openapi({ title: $locale('OrderNo') }), v.default(''), v.min(3))
- orderNo: string;
- @Api.field(v.title($locale('Remark')), v.optional())
- remark?: string;
- @Api.field(v.tableIdentity())
- customerId: TableIdentity;
- }
复制代码
- v.openapi:声明字段的元数据,用于Swagger
- title:采用$locale定义,从而让Swagger元数据支持多语言能力
- v.title:等价于v.openapi({ title: ... })
- TableIdentity:string | number
2. Customer
- @Entity()
- export class EntityCustomer extends EntityBase {
- @Api.field(v.min(3))
- name: string;
- }
复制代码 Model
1. Order
- @Model({ entity: EntityOrder })
- export class ModelOrder extends BeanModelBase {}
复制代码 2. Customer
- @Model({ entity: EntityCustomer })
- export class ModelCustomer extends BeanModelBase {}
复制代码 基于动态关系的查询
现在我们查询订单列表,包含归属的顾客信息:- const orders = await this.scope.model.order.select({
- with: {
- customer: $relationDynamic.belongsTo(
- () => ModelOrder,
- () => ModelCustomer,
- 'customerId',
- ),
- },
- });
复制代码
- $relationDynamic:提供一组工具,用于定义动态关系
- belongsTo:定义多对一的关系
- 参数1:Order模型
- 参数2:Customer模型
- 参数3:设置关联外键customerId
下面我们看一下orders的类型推断效果:
自动推断DTO
现在我们自动推断DTO,并且设为API的返回数据的类型:- const DtoOrderResult = $Dto.get(
- () => ModelOrder,
- {
- with: {
- customer: $relationDynamic.belongsTo(
- () => ModelOrder,
- () => ModelCustomer,
- 'customerId',
- ),
- },
- },
- );
- @Controller('order')
- export class ControllerOrder extends BeanBase {
- @Web.get()
- @Api.body(v.array(v.object(DtoOrderResult)))
- async findAll() {
- return await this.scope.service.order.findAll();
- }
- }
复制代码
- 行1:动态创建DtoOrderResult
- 行17:将DtoOrderResult用于Swagger/Openapi的元数据
下面我们看一下API的Swagger效果:
封装DTO
我们还可以创建一个新的DTO,将前面动态创建的DtoOrderResult封装起来,从而用于其他地方:
在VSCode中,可以通过右键菜单Vona Create/Dto创建DTO的代码骨架:- @Dto()
- export class DtoOrderResult {}
复制代码 然后我们通过继承机制来封装DTO:- const DtoOrderResultDynamic = $Dto.get(
- () => ModelOrder,
- {
- with: {
- customer: $relationDynamic.belongsTo(
- () => ModelOrder,
- () => ModelCustomer,
- 'customerId',
- ),
- },
- },
- );
- @Dto()
- export class DtoOrderResult extends DtoOrderResultDynamic {}
复制代码 现在,我们再使用新创建的DTO来改造前面的API代码:- + import { DtoOrderResult } from '../dto/orderResult.ts';
- @Controller('order')
- export class ControllerOrder extends BeanBase {
- @Web.get()
- + @Api.body(v.array(v.object(DtoOrderResult)))
- + async findAll(): Promise<DtoOrderResult[]> {
- return await this.scope.service.order.findAll();
- }
- }
复制代码
- 行6: 直接传入DtoOrderResult
- 行7: 返回类型为Promise
结语
Vonajs已开源:https://github.com/vonajs/vona。
Vonajs作者正在B站直播撰写技术文档,工作日每晚8:30,欢迎围观:濮水代码直播间
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |