使用 Slick 进行多重 OR 过滤

Multiple OR filtering with Slick

这里我用1列(keyId)和1个值(keyId)过滤了table,结果类型是Optional,是正确的。

override def findByKeyId(keyId: String): Future[Option[Event]] =
    db.run(events.filter(_.keyId === keyId).result.headOption)

现在我需要按 1 列 (keyId) 和多个值进行过滤。

override def findByKeyIdBulk(keyIdSeq: Seq[Option[String]]): Future[Seq[Option[Event]]] = {

    db.run(
      events.filter { event =>
        keyIdSeq
          .map(_.map(keyId => event.keyId === keyId))
          .collect({ case Some(criteria) => criteria })
          .reduceLeftOption(_ || _)
          .getOrElse(true: Rep[Boolean])
      }.result
    ) // Future[Seq[Event]]

  }

在此代码中 Future[Seq[Event]] 类型的表达式不符合 Future[Seq[Option[Event]]]

如何修复?

调用 events.result 将返回 Future[Seq[Event]]。使用 filter 不会改变它,所以结果类型仍然是 Future[Seq[Event]]。为了将其更改为 Future[Seq[Option[Event]]],您必须将值提升为 Option[Event]:

db.run(
  events.filter { event =>
    keyIdSeq
      .map(_.map(keyId => event.keyId === keyId))
      .collect({ case Some(criteria) => criteria })
      .reduceLeftOption(_ || _)
      .getOrElse(true: Rep[Boolean])
  }
  .map(_.map(Option(_))) //lifting Event to Option[Event]
  .result
) // Future[Seq[Option[Event]]]

我认为您误解了将 Option[T] 作为 return 值的意义。返回 Seq[Option[T]] 是反模式,原因如下:

当不能保证您会找到任何东西时,

Option[T] 完全有意义。 FindById 是一个很好的例子,它很有用——我们要么找到一些东西并得到 Some(value),要么我们找不到并得到 None.

但是,如果您计划通过多个 ID 进行查找,并且想要 Seq 个找到的值,那么有两种情况:Seq 为空且未找到任何内容,或者 Seq 包含一些元素。在 Seq 中包含 Option[T] 是没有意义的,因为序列中不会有任何 None。您将被迫使用完全没有意义的额外模式匹配或额外映射。

我认为您最好将类型签名更改为 Future[Seq[Event]]