本文旨在介绍如何在 TypeORM 中使用 Raw sql 表达式来构建更灵活的 Where 查询条件,尤其是在需要避免大量 Or 条件时。通过 Raw 函数,你可以直接在 TypeORM 的查询选项中嵌入原生 SQL 片段,从而实现更精细的查询控制,避免构建过于庞大的 Where 数组,提升代码可读性和性能。
TypeORM 提供了多种方式来构建查询条件,但有时我们需要更底层的控制,或者需要避免构建过于复杂的查询对象。这时,Raw SQL 表达式就派上了用场。 Raw 允许你直接在 TypeORM 的 find 方法的 where 选项中嵌入原生 SQL 片段,从而实现更精细的查询控制。
使用 Raw SQL 表达式
Raw 函数接受一个函数作为参数,该函数接收一个别名(alias)作为参数,并返回一个 SQL 字符串。这个 SQL 字符串会被直接插入到生成的 SQL 查询语句中。
示例:
假设我们有一个 Post 实体,并且想要查询 currentDate 大于某个日期的所有记录。我们可以使用以下代码:
import { DataSource, Raw } from "typeorm"; // 假设 dataSource 已经初始化 async function findPostsAfterDate(dataSource: DataSource, date: string) { const loadedPosts = await dataSource.getRepository("Post").findBy({ currentDate: Raw((alias) => `${alias} > :date`, { date: date }), }); return loadedPosts; }
这段代码将会生成如下 SQL 查询语句:
SELECT * FROM "post" WHERE "currentDate" > '2020-10-06'
参数化查询:
需要注意的是,为了避免 SQL 注入,你应该始终使用参数化查询。在 Raw 函数的第二个参数中,你可以传递一个包含参数的 JavaScript 对象。这些参数会被安全地转义并插入到 SQL 查询语句中。
应用场景:避免大量 Or 条件
回到最初的问题,如果我们需要根据 availableFrom 和 availableTo 字段来筛选数据,并且想要避免使用大量的 Or 条件,我们可以使用 Raw SQL 表达式来实现。
假设我们有如下需求:
- useAvailablePeriod 为 true 时,需要满足 availableFrom <= currentDate 并且 availableTo >= currentDate,或者 availableFrom 或 availableTo 为 NULL。
- useAvailablePeriod 为 false 时,不需要考虑 availableFrom 和 availableTo 字段。
我们可以使用以下代码来实现:
import { DataSource, Raw, LessThanOrEqual, NewsStatus } from "typeorm"; interface Params { categorySeoName: string; } // 假设 dataSource 已经初始化 async function findNews(dataSource: DataSource, params: Params) { const currentDate = new Date(); const newsRepository = dataSource.getRepository("News"); const [news, count] = await newsRepository.findAndCount({ select: { id: true, publishedAt: true, isDisplayed: true, priority: true, availableTo: true, availableFrom: true, useAvailablePeriod: true, }, where: [ { status: NewsStatus.PUBLISHED, newsCategories: { seoName: params.categorySeoName }, useAvailablePeriod: true, availableFrom: Raw((alias) => `(${alias} <= :currentDate OR ${alias} IS NULL)`, { currentDate }), availableTo: Raw((alias) => `(${alias} >= :currentDate OR ${alias} IS NULL)`, { currentDate }), publishedAt: LessThanOrEqual(currentDate), }, { status: NewsStatus.PUBLISHED, newsCategories: { seoName: params.categorySeoName }, useAvailablePeriod: false, publishedAt: LessThanOrEqual(currentDate), }, ], order: { publishedAt: "DESC", priority: "DESC" }, }); return { news, count }; }
在这个例子中,我们使用了 Raw 函数来构建 availableFrom 和 availableTo 的查询条件。 这样,我们就可以避免构建大量的 Or 条件,使代码更加简洁易懂。 注意,这里使用了参数化查询,将 currentDate 作为参数传递给 Raw 函数,避免了 SQL 注入的风险。
注意事项:
- 在使用 Raw SQL 表达式时,务必注意 SQL 注入的风险。始终使用参数化查询,避免直接将用户输入拼接到 SQL 字符串中。
- Raw SQL 表达式会降低代码的可移植性,因为不同的数据库可能使用不同的 SQL 语法。 尽量避免在业务逻辑中使用过于复杂的 SQL 表达式,以便于将来更换数据库。
- 虽然 Raw SQL 表达式提供了更灵活的查询控制,但也增加了代码的复杂性。 在可以使用 TypeORM 提供的其他查询方式时,尽量避免使用 Raw SQL 表达式。
总结:
Raw SQL 表达式是 TypeORM 提供的一个强大的工具,可以帮助我们构建更灵活的查询条件。 在需要避免大量 Or 条件或者需要使用特定数据库的 SQL 特性时,Raw SQL 表达式是一个不错的选择。 但是,在使用 Raw SQL 表达式时,务必注意 SQL 注入的风险,并尽量避免在业务逻辑中使用过于复杂的 SQL 表达式。