使用 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]]
这里我用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]]