Loopback 4中何处执行原生SQL查询及搭建带动态参数的Products REST接口
LoopBack 4 原生SQL查询代码存放位置与带动态参数的产品接口实现
核心放置规则
const result = await repository.execute('SELECT * FROM Products'); 这类原生SQL执行逻辑,必须遵循LoopBack 4的标准分层架构放置,不要直接写在控制器的路由函数内,具体放置位置按照业务复杂度匹配:
- 单表简单原生查询逻辑
放到对应领域的Repository类中,这类文件统一存放在项目的src/repositories目录下。以Products模型为例,对应仓储类为products.repository.ts,类本身继承自DefaultCrudRepository,已经内置了execute方法的实现,只需要在类内部新增自定义方法,把原生SQL逻辑封装成可复用的仓储方法即可。
适配动态name参数的仓储方法示例:// src/repositories/products.repository.ts export class ProductsRepository extends DefaultCrudRepository< Product, typeof Product.prototype.id, ProductRelations > { // 封装带name参数的原生查询 async queryProductByName(name: string) { // 动态参数使用占位符传递,不要直接拼接字符串,避免SQL注入 return await this.execute( 'SELECT * FROM Products WHERE name = $1', [name] ); } } - 跨表/多步复杂查询逻辑
把原生SQL调用逻辑抽到src/services目录下的服务类中,由服务类注入多个关联的Repository实例统一调度,不要把复杂业务逻辑硬绑定到单个Repository类上。
路由层的代码放置逻辑
对应/products/[name]的REST接口逻辑,代码统一放在src/controllers目录下的对应产品控制器文件(如products.controller.ts)中。控制器层只负责接收请求参数、调用上层封装好的仓储/服务方法、返回处理结果,不在控制器内部直接写原生SQL执行逻辑。
接口实现示例:
// src/controllers/products.controller.ts export class ProductsController { constructor( @repository(ProductsRepository) public productsRepo: ProductsRepository ) {} @get('/products/{name}') async getProductDetail( @param.path.string('name') name: string ) { // 直接调用仓储层封装好的原生查询方法 return await this.productsRepo.queryProductByName(name); } }
新手常见放置误区
- 不要将
repository.execute的硬编码逻辑直接写在路由处理函数中,会导致后续重复的查询逻辑无法跨接口复用,也违背LoopBack的分层设计规范。 - 不要把不同业务场景的SQL语句散落在各个代码文件中,所有原生SQL统一在封装好的仓储/服务方法内维护,后续调整查询逻辑时不需要全局翻找零散代码。
- 带动态参数的SQL必须使用数据库驱动支持的占位符传递参数,不要直接将路径传入的
name字符串拼接进SQL语句,避免引入SQL注入风险。
内容的提问来源于stack exchange,提问作者Nico Horn
相关产品推荐
相关产品推荐

