在Slick示例中,有一些连接示例,其中一个结果列可以为空,因为在执行左,右或外连接时可能就是这种情况.例如:
val explicitLeftOuterJoin = for { (c, s) <- Coffees leftJoin Suppliers on (_.supID === _.id) } yield (c.name, s.name.?)
但是,如果我想返回整个映射对象呢?我的意思是:
val explicitLeftOuterJoin = for { (c, s) <- Coffees leftJoin Suppliers on (_.supID === _.id) } yield (c, s.?)
这似乎不起作用,因为它抱怨"找不到scala.slick.lifted.TypeMapper [供应商]类型的证据参数的隐含值".基本上我想要它返回一个元组列表(咖啡,选项[供应商])
为什么这不起作用,它的修复方法是什么?特别是,因为这很好:
val q = for { c <- Coffees s <- Suppliers } yield (c, s)
(我知道这是一个内部联接)
更新: 这将解决并简单地在2014年底的Slick 3.0中工作,不再需要以下解决方法
这是目前Slick的一个限制.你得打电话.?在每一列上单独.但是,您可以将一个?
在表类中调用的函数放在一个中心位置,从而获得.在完整的行上.这个有趣的示例代码包含一个涉及一些生成代码的通用解决方案.我们还有一个增加自动生成的公关?排队的方法.
从长远来看,我们将在Slick中支持外连接的变体,其中Slick完全了解所涉及的类型,您无需指定.任何地方.现在我们必须忍受涉及代码生成的变通方法.
不是最干净的解决方案(使用scalaz 7.0.6和无形2.0.1),但这现在适用(Slick 2.0.1):
使用?
上面的投影,可以创建一个Slick投影来转换Option
values => Option[TupleN]
=> 的元组Option[YourClass]
.
option
投影注意: sequence
用于将Option
值的元组转换为Option[TupleN]
.代码for sequence
在本答案的底部定义.
添加到Suppliers
.假设Supplier
是一个案例类.
import scalaz._, Scalaz._ import SequenceTupleOption._ def option = (id.?, name.?, street.?) <> (optionApply, optionUnapply) def optionApply(t: (Option[Int], Option[String], Option[String])): Option[Comment] = { sequence(t).map(Supplier.tupled) } def optionUnapply(oc: Option[Supplier]): Option[(Option[Int], Option[String], Option[String])] = None
option
投影val explicitLeftOuterJoin = for { (c, s) <- Coffees leftJoin Suppliers on (_.supID === _.id) } yield (c, s.option)
sequence
,将Option
值的元组转换为Option[TupleN]
这是特拉维斯布朗写的难题.sequence
从元组Option
值转换为Option[TupleN]
(使用scalaz和无形).
import scalaz._, Scalaz._ import shapeless._, ops.hlist.{ RightFolder, Tupler } object SequenceTupleOption { object applicativeFolder extends Poly2 { implicit def caseApplicative[A, B <: HList, F[_]](implicit app: Applicative[F] ) = at[F[A], F[B]] { (a, b) => app.ap(a)(app.map(b)(bb => (_: A) :: bb)) } } def sequence[T, EL <: HList, L <: HList, OL <: HList, OT](t: T)(implicit gen: Generic.Aux[T, EL], eq: EL =:= L, folder: RightFolder.Aux[L, Option[HNil], applicativeFolder.type, Option[OL]], tupler: Tupler.Aux[OL, OT] ): Option[OT] = eq(gen.to(t)).foldRight(some(HNil: HNil))(applicativeFolder).map(tupler(_)) }
用途sequence
:
import scalaz._, Scalaz._ import SequenceTupleOption._ case class Person(id: Int, name: String, age: Int) val t = (Option(1), Option("Bob"), Option(40)) val person: Option[Person] = sequence(t).map(Person.tupled) // Some(Person(1,Bob,40))
什么sequence
(不适当的类型)的高级概述:
将元组转换为Option
无形HList[Option[_]]
.
sequence
过了HList[Option[_]]
一个Option[HList[_]]
将HList
后面转换为元组.