如何使用 typeORM 制作复杂的嵌套 where 条件?

Tom*_*mmy 16 sql typescript typeorm

我有多个嵌套的 where 条件,并且希望生成它们而无需使用 typeORM 进行太多代码重复。

SQL where 条件应该是这样的:

 WHERE "Table"."id" = $1
AND
"Table"."notAvailable" IS NULL
AND
(
  "Table"."date" > $2
  OR
  (
    "Table"."date" = $2
    AND
    "Table"."myId" > $3
  )
)
AND
(
  "Table"."created" = $2
  OR
  "Table"."updated" = $4
)
AND
(
  "Table"."text" ilike '%search%'
  OR
  "Table"."name" ilike '%search%'
)
Run Code Online (Sandbox Code Playgroud)

但似乎FindConditions不可能让它们嵌套,所以我必须AND在 FindConditions 数组中使用所有可能的组合。并且不可能将其拆分为.where().andWhere()导致andWhere无法使用对象文字。

是否有另一种可能性可以在不使用原始 SQL 的情况下使用 typeORM 实现此查询?

Suf*_*ane 31

使用 queryBuilder 时,我建议Brackets 按照 Typeorm 文档中所述使用: https: //typeorm.io/#/select-query-builder/adding-where-expression

你可以这样做:

createQueryBuilder("user")
    .where("user.registered = :registered", { registered: true })
    .andWhere(new Brackets(qb => {
        qb.where("user.firstName = :firstName", { firstName: "Timber" })
          .orWhere("user.lastName = :lastName", { lastName: "Saw" })
    }))
Run Code Online (Sandbox Code Playgroud)

这将导致:

SELECT ... 
FROM users user
WHERE user.registered = true 
AND (user.firstName = 'Timber' OR user.lastName = 'Saw')
Run Code Online (Sandbox Code Playgroud)


Fun*_*nly 20

我认为您正在混合从 TypeORM 检索实体的两种方法,从存储库和查询生成器中查找。它们FindConditions用在 find 函数中。该andWhere函数由查询生成器使用。当构建更复杂的查询时,使用查询构建器通常更好/更容易。


查询生成器

使用查询构建时,您可以更自由地确保查询符合您的需要。您可以随意添加任何 SQL:

const desiredEntity = await connection
  .getRepository(User)
  .createQueryBuilder("user")
  .where("user.id = :id", { id: 1 })
  .andWhere("user.date > :date OR (user.date = :date AND user.myId = :myId)",
    { 
      date: specificCreatedAtDate,
      myId: mysteryId,
    })
  .getOne();
Run Code Online (Sandbox Code Playgroud)

请注意,根据您使用的数据库,您在此处使用的实际 SQL 需要兼容。因此,使用这种方法也可能存在缺点。您将把您的项目绑定到特定的数据库。如果您使用关系,请务必阅读有关可以设置的表的别名的信息,这会很方便。


存储库

您已经看到这不太舒服。这是因为find函数或更具体的findOptions函数正在使用对象来构建 where 子句。这使得实现适当的接口来并排实现嵌套ANDOR子句变得更加困难。为此(我认为)他们选择了拆分ANDOR子句。这使得界面更具声明性,并且意味着您必须将OR子句拉到顶部:

const desiredEntity = await repository.find({
  where: [{
    id: id,
    notAvailable: Not(IsNull()),
    date: MoreThan(date)
  },{
    id: id,
    notAvailable: Not(IsNull()),
    date: date
    myId: myId
  }]
})
Run Code Online (Sandbox Code Playgroud)

我无法想象看看所需查询的大小,这段代码会非常高效。

或者,您可以使用Raw查找助手。这将要求您重写每个字段的子句,因为您一次只能访问一个别名。您可以猜测列名或别名,但这将是非常糟糕的做法并且非常不稳定,因为您无法轻松直接控制它。