- 后端
- 微服务
【免费下载链接】loopback-next
LoopBack makes it easy to build modern API applications that require complex integrations.
本文是 LoopBack 4(loopback-next仓库)中Model概念的技术指南,围绕 docs/site/Model.md 展开,系统讲解如何用@model与@property装饰器定义领域模型、配置模型元数据、隐藏属性、默认作用域、ID 属性、数组属性、自定义校验规则,以及模型与数据库表/集合的映射和 JSON Schema 推断。读完本文,你将掌握在 LoopBack 4 应用中从零定义Entity/Model领域对象并安全对接 REST、OpenAPI 与各类数据库连接器的完整实战能力。
什么是 LoopBack 4 模型(Model)
在 LoopBack 4 中,模型(Model)用来描述业务领域对象(domain objects),例如Customer、Address、Order。一个模型通常定义一组属性(property),每个属性带有名称、类型以及其他约束。
关键设计理念是:模型只描述数据的形状(shape),行为(如 CRUD 操作)由仓库(Repository)添加。这与 LoopBack 3.x 中"模型也实现行为"的旧模式有本质区别;同时,同一个模型可以与多个不同的 Repository 搭配使用。
模型可被用于在线(wire)传输或系统间的数据交换。例如,一个符合Customer模型定义的 JSON 对象,可以被放到 REST/HTTP 请求体中来创建新客户,也可以存入 MongoDB 这类文档数据库。模型定义还能映射为其他形式——关系数据库 Schema、XML Schema、JSON Schema、OpenAPI Schema 或 gRPC 消息定义,反之亦然。
Entity 与 Model:两种细微不同的领域对象
LoopBack 4 将领域对象区分为两类:
- Entity(实体):拥有身份标识(ID)的领域对象,其相等性基于身份。例如
Customer应建模为Entity,因为每个客户都有唯一的 customer id,两个具有相同 customer id 的Customer实例指向同一个客户,因此相等。
import {Entity, model, property} from '@loopback/repository'; @model() export class Customer extends Entity { @property({id: true}) id: string; @property() name: string; @property() email: string; constructor(data?: Partial<Customer>) { super(data); } }- Model(模型):没有身份标识的领域对象,其相等性基于结构值(structural value)。例如
Address可建模为Model,因为两个美国地址只要街道号、街道名、城市和邮编相同,就是相等的。
import {Model, model, property} from '@loopback/repository'; @model() export class Address extends Model { @property() streetNum: number; @property() streetName: string; @property() city: string; @property() zipCode: string; constructor(data?: Partial<Address>) { super(data); } }当前项目通过@loopback/repository模块提供专用装饰器@model和@property,用于为 TypeScript/JavaScript 类附加元数据。在源码中,Model与Entity的基类都定义于 packages/repository/src/model.ts:Model提供toJSON()/toObject()序列化能力,Entity extends Model额外提供getId()、getIdObject()、getIdProperties()、buildWhereForId()等与主键相关的工具方法。
定义模型:@model 与 @property 基础用法
一个典型的 LoopBack 4 模型用 TypeScript 编写,使用@model装饰类、@property装饰类成员(属性):
import {Entity, model, property} from '@loopback/repository'; @model({setting: {hiddenProperties: 'id'}}) export class User extends Entity { @property({ type: 'number', id: true, generated: true, }) id: number; @property({ type: 'string', required: false, }) des?: string; constructor(data?: Partial<User>) { super(data); } }LoopBack 4 还提供了命令行工具(CLI)lb4 model来生成模型。从源码看,CLI 生成器位于 packages/cli/generators/model/index.js,它会依次提示模型名称、基类(Entity/Model)以及需要添加的属性,直到输入空白属性名为止。
本质上,LoopBack 中的模型就是一个简单的 JavaScript 类。借助@model/@property装饰器的可扩展性,框架能够操作元数据,甚至与 JSON Schema 生成集成。例如下面这个不含 ID 的简单模型:
import {model, property} from '@loopback/repository'; @model() export class Customer { @property() email: string; @property() isMember: boolean; @property() cart: ShoppingCart; }@model装饰器还可以接收jsonSchema来定制为该模型类推断出的 JSON Schema:
@model({ jsonSchema: { title: 'Customer', required: ['email'], }, }) export class Customer { // ... }模型相关的常见任务
- 在运行时定义模型:使用
defineModelClass()等工具在运行时动态构建模型; - 从数据库发现模型:根据数据库现有表/集合反向生成模型定义。
模型元数据:装饰器背后的实现机制
LoopBack 4 通过@model和@property收集模型的元数据。要让这两个装饰器生效,类需要继承Entity(或Model)并使用装饰器标注:
import {model, property, Entity} from '@loopback/repository'; @model() export class Product extends Entity { @property({ id: true, description: 'The unique identifier for a product', }) id: number; @property() name: string; @property() slug: string; constructor(data?: Partial<Product>) { super(data); } }从源码 packages/repository/src/decorators/model.decorator.ts 可以看到装饰器的真实工作流程:
- 框架定义了三个元数据访问键(MetadataAccessor):
MODEL_KEY('loopback:model'):存储@model传入的ModelDefinitionSyntax;MODEL_PROPERTIES_KEY('loopback:model-properties'):存储@property传入的属性定义;MODEL_WITH_PROPERTIES_KEY('loopback:model-and-properties'):合并后的完整模型定义。
@model(definition)装饰器会调用buildModelDefinition(target, def):通过MetadataInspector.getAllPropertyMetadata(MODEL_PROPERTIES_KEY, prototype)收集所有属性元数据;对每个属性,若没有显式type,则回退到 TypeScript 的设计期类型MetadataInspector.getDesignTypeForProperty(...),取不到时抛出错误码为CANNOT_INFER_PROPERTY_TYPE的异常;若属性设置了hidden: true,则自动把该属性名追加进settings.hiddenProperties数组。- 最终构建的
ModelDefinition被挂在类的definition静态属性上,关系元数据(RELATIONS_KEY)也会被合并进去。
除了定义本身,@model与@property还支持一系列设置。例如,默认情况下 LoopBack 4 类会禁止接收未在类型定义中声明的额外属性;当使用 MongoDB 这类支持自由格式属性的 NoSQL 数据库时,可通过@model关闭该约束。详见下文@model装饰器与@property装饰器两个小节。
@model 装饰器详解:模型定义(ModelDefinitionSyntax)
@model可以不带参数使用,也可以传入ModelDefinitionSyntax对象:
@model({ name: 'Category', settings: { // etc... }, // 属性通过下面的 @property 装饰器定义 }) class Category extends Entity { // etc... @property({type: 'number'}) categoryId: number; }name可以省略,因为@model装饰器已经知道模型类的名称(源码中通过definition.name ?? target.name回退取类名):
@model() class Product extends Entity { name: string; // other properties... }注意:如果你用过 LoopBack 3,LB4 的
model装饰器与 LB3 并不完全相同。例如,属性(properties)和关系(relations)不能通过model装饰器定义,只能通过@property与关系装饰器完成。请参考下文"支持项"与"不支持项"两节。
模型定义支持项(Supported Entries of Model Definition)
settings中目前内置支持以下条目:
| Property | Type | Default | Description |
|---|---|---|---|
name | String | None | 模型名称。 |
settings.description | String | None | 模型的可选描述。目前仅支持字符串类型。 |
settings.forceId | Boolean | true | 设为true可阻止客户端手动设置自动生成的 ID 值。 |
settings.hiddenProperties | Array of String | None | 从响应体(.toJSON()输出)中隐藏的属性列表。详见下文 隐藏属性。 |
settings.scope | Object | N/A | 作用域,将应用于该模型仓库发起的每一次查询。详见下文 Scope。 |
settings.strict | Boolean or String | true | 指定模型是否只接受预定义的属性,可选值:
|
需要深入源码的读者,可对照查看 legacy-juggler-bridge 与 model-builder 的实现;其中legacy-juggler-bridge.ts中可见创建模型时显式传入{strict: true}等默认配置。
LB3 中不再支持的条目(Unsupported Entries)
如果你是 LB3 用户,以下旧条目在 LB4 中已不可用:
| Property | Description |
|---|---|
acls | (待定) |
base | 该条目不再使用。LB4 采用 TypeScript/JavaScript 常规的类继承方式:@model() class MySuperModel extends MyBaseModel {...} |
excludeBaseProperties | (待定) |
http | 该条目在 LB3 中影响 HTTP 配置。LB4 中 HTTP 配置由控制器成员与 REST 服务器推断,此字段不再适用。 |
options | (待定) |
plural | 属于 LB3 的 HTTP 配置的一部分,与http一样不再适用。 |
properties | 不再使用,LB4 引入了@property装饰器来定义模型属性。 |
relations | 随着仓库(Repository)的引入,LB4 中关系由关系装饰器定义,参见 Relations。 |
remoting.normalizeHttpPath | 属于 LB3 的 HTTP 配置的一部分,不再适用。 |
replaceOnPUT | 不再支持:LB4 控制器脚手架生成的 PUT 始终调用replaceById,如需可自行修改生成代码改用patchById。 |
隐藏属性(Hidden Properties)
隐藏属性仍然存储于数据库、在 JS/TS 代码中可访问、可通过 POST/PUT/PATCH 请求设置,但它们会从响应体(.toJSON()输出)中被移除。典型的应用场景是密码字段等敏感数据。
隐藏属性有两种配置方式:
方式一:模型级hiddenProperties设置(还可以隐藏从父模型继承来的属性):
@model({ settings: { hiddenProperties: ['password'] } }) class MyUserModel extends Entity { @property({id: true}) id: number; @property({type: 'string'}) email: string; @property({type: 'string'}) password: string; ... }方式二:属性级hidden: true:
@model() class MyUserModel extends Entity { @property({id: true}) id: number; @property({type: 'string'}) email: string; @property({type: 'string', hidden: true}) password: string; ... }从源码看,属性级hidden: true在buildModelDefinition阶段就会被收集并合并进settings.hiddenProperties(见 packages/repository/src/decorators/model.decorator.ts);而Model.toJSON()在序列化时逐个属性检查hiddenProperties并跳过其中的键(见 packages/repository/src/model.ts)。
Scope:模型级默认查询作用域
Scope允许你设置一个作用于模型仓库每一次查询的默认范围。若希望某个范围应用到所有查询,就在@model的settings.scope中声明。例如:
@model({ settings: { scope: { limit: 2, where: {deleted: false} }, } }) export class Product extends Entity { ...此后,任何带查询参数的 CRUD 操作都会在默认作用域下执行。例如,假设有上述 scope,一次find调用:
await ProductRepository.find({offset: 0});等价于:
await ProductRepository.find({ offset: 0, limit: 2, where: {deleted: false}, });@property 装饰器详解
LoopBack 4 使用@property装饰器定义模型属性:
@model() class Product extends Entity { @property({ name: 'name', description: "The product's common name.", type: 'string', }) public name: string; @property({ type: 'number', id: true, }) id: number; }属性定义通用属性表
以下是属性定义(PropertyDefinition)的通用字段:
| Key | Required? | Type | Description |
|---|---|---|---|
default | No | Any* | 属性的默认值,类型必须与type一致。注意:如果同时设置了default和required: true,POST/PUT 请求体仍需包含该字段——因为 LoopBack 遵循 OpenAPI 标准,required意味着用户必须始终在请求中提供该字段。 |
defaultFn | No | String | 用于生成默认值的函数名,必须是以下之一:
|
description | No | String or Array | 属性的文档说明。长描述可以拆成字符串数组(多行)以保持行宽可控,例如:["LoopBack 4 is a highly extensible Node.js and TypeScript framework", "for building APIs and microservices.", "..."] |
doc | No | String | 属性文档。已废弃,请改用description。 |
id | No | Boolean | 该属性是否为唯一标识,默认false。详见下文 ID 属性。 |
index | No | Boolean | Object | 布尔值表示该属性是否为数据库索引列(字段);也可以是对象,如index: {unique: true}让属性唯一。注意:是否支持取决于连接器。 |
required | No | Boolean | 创建或更新模型实例时,请求体是否必须包含该属性,默认false。注意:遵循 OpenAPI 标准,即使设置了default,POST/PUT 请求缺省该字段仍可能被拒绝。 |
type | Yes | String | 属性类型,可以是 LoopBack 类型 中描述的任何类型。 |
hidden | No | Boolean | 从响应体(.toJSON()输出)隐藏该属性。详见上文 隐藏属性。 |
ID 属性
LoopBack 4 期望每个模型都有一个能唯一标识模型实例的ID 属性(ID property)。
重要:LB4 目前不支持复合键(composite keys),例如用多个源键关联两张表。
要显式指定某个属性为 ID,将选项中的id设为true。id的值只能是:
true:该属性是 ID;false(或任何可转换为 false 的值):该属性不是 ID(默认)。
在数据库术语中,ID 属性就是主键列(primary key column)。例如:
@property({ type: 'number', id: true, }) id: number;LoopBack 的 自动迁移(auto-migration)可以根据模型定义创建关系数据库 Schema。以下是可用于 auto-migration / auto-update 的 ID 属性设置:
| Key | Required? | Type | Description |
|---|---|---|---|
generated | No | Boolean | 用于 auto-migrate。表示 ID 将由数据库自动生成。设为true时,id 值将由数据库按其默认类型生成(如 MySQL 为 integer、MongoDB 为 string)。 |
useDefaultIdType | No | Boolean | 用于 auto-migrate。需要自动生成非默认类型的属性值时设为false。例如 PostgreSQL 想用 uuid 作为 id:id 类型设为 string、generated设为true、useDefaultIdType设为false。具体请查阅各连接器的 README。 |
关于 ID 的实用提示:
- 如果模型由数据库支撑,LoopBack 的 CRUD 方法要求模型拥有
id属性; - 没有任何
id属性的模型只能在不挂接数据库的情况下使用; - 若 ID 属性
generated为true,由连接器决定自动生成键的类型(例如 SQL Server 默认为number),可通过useDefaultIdType: false覆盖; - 若希望 LoopBack 4 基于模型定义自动创建关系数据库 Schema,参见 Database Migration;数据库迁移/发现的细节与示例始终以 Database Connectors 为准。
在源码 packages/repository/src/model.ts 中可以看到一个联动逻辑:当ModelDefinition.addProperty检测到属性同时满足id === true、generated === true且未显式声明useDefaultIdType时,会自动把useDefaultIdType置为false。
数组属性装饰器(@property.array)
由于 JavaScript 数组本身不携带成员类型信息(遍历数组只能判断成员是原始类型、对象还是函数,无法知道对象/函数的具体结构),LoopBack 无法自动推断数组元素的类型。因此要求使用@property.array装饰器来补充数组属性的类型推断元数据:
@model() class Order extends Entity { @property.array(Product) items: Product[]; } @model() class Thread extends Entity { // 注意:即使是原始类型数组也必须使用! @property.array(String) posts: string[]; }@property.array还支持可选的第二参数,以与@property相同的方式定义或覆盖元数据:
@model() class Customer extends Entity { @property.array(String, { name: 'names', required: true, }) aliases: string[]; }数组元素的 JSON Schema 额外属性可以通过第二参数中的jsonSchema提供:
@model() class Customer extends Entity { @property(String, { jsonSchema: { format: 'email', }, }) email: string; }对于@property.array,jsonSchema作用于数组元素类型而非数组本身:
@model() class TestModel { @property.array(String, { jsonSchema: { format: 'email', minLength: 5, maxLength: 50, transform: ['toLowerCase'], }, }) emails?: string[]; }要定义嵌套数组属性,必须提供jsonSchema字段来描述子数组。例如:
@model() class TestModel { // 也可以写成 @property.array('array') @property.array(Array, { jsonSchema: { type: 'array', items: {type: 'string'}, }, }) nestedArr: Array<Array<string>>; }如果缺少jsonSchema字段,会得到如下报错:
You must provide the "jsonSchema" field when define a nested array property
从源码 packages/repository/src/decorators/model.decorator.ts 可见,@property.array在运行时通过MetadataInspector.getDesignTypeForProperty校验属性设计期类型必须是Array,否则抛出ERR_PROP_NOT_ARRAY('@property.array can only decorate array properties!'),随后以{type: Array, itemType}为基础合并用户定义并委托给@property。
自定义校验规则与自定义错误消息
可以在属性的jsonSchema字段中指定校验规则,并搭配自定义错误消息:
@model() class Product extends Entity { @property({ name: 'name', description: "The product's common name.", type: 'string', // JSON 校验规则 jsonSchema: { minLength: 10, maxLength: 30, errorMessage: 'Name should be between 10 and 30 characters.', }, }) public name: string; }如果你希望为每条未通过的校验规则返回各自的错误消息,可以把errorMessage配置成对象:
jsonSchema: { minLength: 10, maxLength: 30, errorMessage: { // 对应的错误消息 minLength: 'Name should be at least 10 characters.', maxLength: 'Name should not exceed 30 characters.', } }关于请求体校验的完整实现细节,请参考 Parsing requests(请求解析)。
属性类型的推断限制
@property装饰器依赖 LoopBack 的 metadata 包来确定属性的类型。目前属性类型必须显式声明——要么写在该属性本身上,要么通过@property的type选项指定。别名类型或从类/接口中抽取的类型(例如public name: OtherClass['otherProperty'])无法正常工作:TypeScript 当前生成元数据的方式存在局限,这类写法会导致属性类型在生成的 OpenAPI 规范中被解析为空对象,而不是期望的类型。
反例(结果会生成"__metadata("design:type", Object)"而非String):
export class StandardUser { public email: string; public anotherProperty: boolean; } @model() export class UserModel { @property() public email: StandardUser['email']; // => 生成 "__metadata("design:type", Object)" 而非 String }正例(直接声明类型,属性类型信息即为String):
@model() class Product extends Entity { @property() public name: string; // 该属性的类型信息是 String。 }ENUM 属性(变通方案)
目前
enum类型尚未被原生支持。下面是允许你使用该类型的变通方案。
@property装饰器可通过jsonSchema定制模型属性推断出的 JSON Schema。对于enum类型,可以这样用:
enum QueryLanguage { JSON = 'json', SQL = 'sql', MONGO = 'mongo' } // ... @property({ type: 'string', required: true, jsonSchema: { enum: Object.values(QueryLanguage), }, }) queryLanguage: QueryLanguage;模型如何映射到数据库表/集合
一个常见问题是:如何配置与模型类名不同的自定义表/集合名称?
无论通过 CLI(lb4 model)、模型迁移 还是模型发现建立模型与数据库表/集合的对应关系,模型/属性都会基于某种约定或连接器特定设置映射到对应的表/列。
当没有连接器特定设置时,例如:
@model() export class MyModel extends Entity { @property({ type: 'number', required: true, id: true, }) id: number; @property({ type: 'string', required: false, }) myName?: string; }连接器会按各自的约定映射:以 Oracle 连接器为例,它会在默认 Schema 下寻找名为MYMODEL的表,并把属性id、myName映射为表中的ID、MYNAME列——因为 UPPERCASE(大写)是 Oracle 数据库的默认命名习惯。PostgreSQL 连接器则会在默认 Schema 下寻找小写表名mymodel以及列id、myname。一方面,如果数据库已有默认命名的表/列会很方便;另一方面,如果找不到默认名称的表/列就会带来麻烦。
重要:不同数据库连接器的具体机制可能有差异(例如有的没有
schema概念;并非所有连接器都支持自定义配置,如 Cloudant)。务必查阅对应的数据库连接器文档。
数据映射属性(Data Mapping Properties)
模型定义的settings中,以下字段通过settings.<connectorName>描述/定制数据库中的 Schema 或表/集合名称:
| Property | Type | Description |
|---|---|---|
[connectorName].schema | String | 表所在的 schema。 |
[connectorName].table | String | 表名,用于 SQL 数据库。 |
[connectorName].collection | String | 表名(集合名),用于 NoSQL 数据库。 |
属性定义的以下通用字段则通过<connectorName>.<propName>描述数据库中的列:
| Property | Type | Description |
|---|---|---|
columnName | String | 列名,用于 SQL 数据库。 |
fieldName | String | 列名(字段名),用于 NoSQL 数据库。 |
dataType | String | 数据库中定义的数据类型。 |
dataLength | Number | 数据长度。 |
dataPrecision | Number | 数值精度。 |
dataScale | Number | 数值小数位数。 |
nullable | Boolean | 为true时数据可以为 null。 |
下面的例子展示了如何在 PostgreSQL 数据库中配置与模型不同的自定义表/列名及其他设置:
@model({ settings: { postgresql: {schema: 'quarter2', table: 'my_model'}, // 自定义名称 }, }) export class MyModel extends Entity { @property({ type: 'number', required: true, id: true, postgresql: { columnName: 'custom_id', dataType: 'integer', dataLength: null, dataPrecision: null, dataScale: 0, nullable: 'NO', }, }) id: number; @property({ type: 'string', required: false, postgresql: { columnName: 'my_name', dataType: 'text', dataLength: 20, dataPrecision: null, dataScale: 0, nullable: 'NO', }, }) myName?: string; }通过上述映射,可以配置与模型不同的自定义名称。上例中,模型属性id映射到表my_model中的列custom_id。
JSON Schema 推断
使用@loopback/repository-json-schema模块可以从带装饰器的模型构建 JSON Schema。类型信息从@model与@property装饰器中推断;该模块提供getJsonSchema函数读取装饰器存储的元数据来构建模型对应的 JSON Schema:
import {model, property} from '@loopback/repository'; import {getJsonSchema} from '@loopback/repository-json-schema'; @model() class Category { @property() name: string; } @model() class Product { @property({required: true}) name: string; @property() type: Category; } const jsonSchema = getJsonSchema(Product);上面的jsonSchema会返回:
{ "title": "Product", "properties": { "name": { "type": "string" }, "type": { "$ref": "#/definitions/Category" } }, "definitions": { "Category": { "properties": { "name": { "type": "string" } } } }, "required": ["name"] }如果模型定义中的某个属性指定了自定义类型,就会为该类型生成引用($ref)字段,并在 Schema 顶层创建definitions子 Schema。definitions子 Schema 会通过递归调用getJsonSchema构建其属性,从而支持复杂、嵌套的自定义类型定义——上例中Product的属性type使用了自定义类型Category,正是这一机制的体现。
从源码 packages/repository-json-schema/src/build-schema.ts 可以看到,getJsonSchema会先按选项键(buildModelCacheKey,如'modelOnly'、'modelWithRelations')在类元数据缓存中查找,未命中时才调用modelToJsonSchema生成并写回缓存,因此重复调用是高效的。配套的getJsonSchemaRef则返回形如{$ref: '#/definitions/Product', definitions: {...}}的引用式 Schema,便于多个端点共享同一份定义。
getJsonSchema还接受JsonSchemaOptions选项对象(同样定义于 build-schema.ts):
title?: string:定制生成 Schema 的标题,在使用exclude等选项导致自动标题难以阅读时很有用;includeRelations?: boolean:为模型关系定义导航属性(navigational properties);partial?: boolean | 'deep':将所有属性标记为可选(常用于描述 PATCH 端点的请求体);设为'deep'时对嵌套模型实例同样生效;该选项会被非空的optional覆盖;exclude?: (keyof T)[]:从 Schema 中排除的模型属性列表;optional?: (keyof T)[]:标记为可选的属性列表,非空时覆盖partial。
支持的 JSON 关键字(Supported JSON Keywords)
该特性仍在完善中。
以下是可显式传入装饰器以更好地定制生成 JSON Schema 的关键字:
| Keywords | Decorator | Type | Default | Description |
|---|---|---|---|---|
| title | @model | string | model name | 模型名称 |
| description | @model | string | None | 模型描述 |
| array | @property | boolean | None | 指定属性是否为数组 |
| required | @property | boolean | false | 指定属性是否必填 |
与其他 ORM/ODM 的配合
你可能决定在 LoopBack 应用中使用替代的 ORM/ODM。LoopBack 4 不再要求你以它自己的模型格式提供数据来支撑路由——这意味着你可以自由修改自己的类以适配这些 ORM/ODM。
不过也要注意:提供的 Schema 装饰器对这些 ORM/ODM 将不再起作用;而且某些框架可能提供同名冲突的装饰器(例如另一个@model装饰器),这种情况下可能需要避免使用 LoopBack 自带的 juggler 装饰器。仓库中也有现成的实践参考,例如 Using-Sequelize-with-LoopBack 与 Using-TypeORM-with-LoopBack 分别演示了在 LoopBack 4 中接入 Sequelize 与 TypeORM 的完整方式。
总结
模型是 LoopBack 4 数据层的基石:@model负责把类声明为模型并写入ModelDefinition,@property负责描述每个属性的类型、ID、默认值、必填性与校验规则。两者配合可实现隐藏属性、默认查询作用域、数组与嵌套类型、自定义校验消息、数据库表/集合的定制映射以及 JSON Schema 的自动推断。理解这些装饰器背后基于 metadata 包的元数据机制(packages/repository/src/decorators/model.decorator.ts)与序列化实现(packages/repository/src/model.ts),将帮助你更自如地结合 Repository、Relations 与各类数据库连接器构建完整的业务 API。
- 后端
- 微服务
【免费下载链接】loopback-next
LoopBack makes it easy to build modern API applications that require complex integrations.
相关推荐
LoopBack 4 Code-First API 定义:从 @model、@property 到路由装饰器与 OpenAPI 规范生成
LoopBack 4 Code First API 定义:从 @model、@property 到路由装饰器与 OpenAPI 规范生成 在 LoopBack
后端微服务LoopBack 4 模型属性类型(LoopBack Types)完全指南:从 `@property` 装饰器到运行时定义
LoopBack 4 模型属性类型(LoopBack Types)完全指南:从 @property 装饰器到运行时定义 LoopBack 4( @loopbac
后端微服务LoopBack 4 Model 生成器(lb4 model)完全指南:交互式创建 Entity 与 Model 类
LoopBack 4 Model 生成器(lb4 model)完全指南:交互式创建 Entity 与 Model 类 lb4 model 是 LoopBack
后端微服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考