Scala 光滑的左/右/外部连接,带选装件

Scala 光滑的左/右/外部连接,带选装件,scala,slick,Scala,Slick,在光滑的示例中,有几个连接示例,其中一个结果列可以为null,就像执行左、右或外连接时一样。例如: val explicitLeftOuterJoin = for { (c, s) <- Coffees leftJoin Suppliers on (_.supID === _.id) } yield (c.name, s.name.?) val explicitLeftOuterJoin=for{ (c,s)更新:这将在2014年底解决,只需在Slick 3.0中工作即可,不再需要以

在光滑的示例中,有几个连接示例,其中一个结果列可以为null,就像执行左、右或外连接时一样。例如:

val explicitLeftOuterJoin = for {
  (c, s) <- Coffees leftJoin Suppliers on (_.supID === _.id)
} yield (c.name, s.name.?)
val explicitLeftOuterJoin=for{
(c,s)更新:这将在2014年底解决,只需在Slick 3.0中工作即可,不再需要以下解决方法

这是目前Slick的一个限制。您必须对每一列单独调用。?。但是,您可以在表类中放置一个名为
的函数,该函数将在中心位置执行此操作,从而获得完整的行。?。这包含一个涉及一些生成代码的通用解决方案。我们还提供了一个队列


从长远来看,我们将在Slick中支持一种外部联接的变体,其中Slick完全了解所涉及的类型,您无需指定。?任何地方。目前,我们必须使用涉及代码生成的变通方法。

除上述答案外: 如果您有一个扩展表的类,并且您的*投影如下所示:

def * = (col1, col2, col3)
比您的?函数看起来更像:

def ? = (col1.?, col2.?, col3.?)
如果已定义此类函数,则可以编写:

for {
    (x,y) <- x leftJoin y on (...)
} yield (x, y.?)
用于{
(x,y)不是最干净的解决方案(使用scalaz 7.0.6和shapeless 2.0.1),但这一解决方案目前有效(Slick 2.0.1):

使用上面的
投影,可以创建一个平滑的投影来转换
选项的元组
值=>
选项[TupleN]
=>
选项[YourClass]

添加
选项
投影 注意:
序列
用于将
选项
值的元组转换为
选项[TupleN]
序列
的代码定义在此答案底部

添加到
供应商
。假设
供应商
是案例类

  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
高级:
序列
,将
选项
值的元组转换为
选项[TupleN]
这是。
序列
选项
值的元组转换为
选项[TupleN]
的困难部分(使用scalaz和shapeless)

序列
功能的高级概述(类型不正确):

  • Option
    的元组转换为不成形的
    HList[Option[\uz]]
  • 序列
    HList[Option[\u]]]
    Option[HList[\u]]]
  • HList
    转换回元组

  • 在Slick 3.1.1中,正确答案很简单(如一些评论中所述):

    用于{
    
    (c,s)与stackoverflow.com/questions/14990365/有关,您能给出一个关于table类的合适的
    实现的示例吗?看看Markus的下一个答案:
    def?=(col1.?,col2.?,col3.)
    cvogt,Slick 2.2是否有任何更新?看起来下一个版本是3.02.2,已重命名为3.0。这将为
    s
    生成一个
    Rep[选项[供应商]]
    ,而且无法使用。
    for {
        (x,y) <- x leftJoin y on (...)
    } yield (x, y.?)
    
      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
    
    val explicitLeftOuterJoin = for {
      (c, s) <- Coffees leftJoin Suppliers on (_.supID === _.id)
    } yield (c, s.option)
    
    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(_))
    
    }
    
    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))
    
    for {
      (c, s) <- coffees joinLeft suppliers on (_.supID === _.id)
    } yield (c, s)