使用Option进行左/右/外连接

 Carre陈 发布于 2023-02-12 19:05

在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)

(我知道这是一个内部联接)

2 个回答
  • 更新: 这将解决并简单地在2014年底的Slick 3.0中工作,不再需要以下解决方法

    这是目前Slick的一个限制.你得打电话.?在每一列上单独.但是,您可以将一个?在表类中调用的函数放在一个中心位置,从而获得.在完整的行上.这个有趣的示例代码包含一个涉及一些生成代码的通用解决方案.我们还有一个增加自动生成的公关?排队的方法.

    从长远来看,我们将在Slick中支持外连接的变体,其中Slick完全了解所涉及的类型,您无需指定.任何地方.现在我们必须忍受涉及代码生成的变通方法.

    2023-02-12 19:07 回答
  • 不是最干净的解决方案(使用scalaz 7.0.6和无形2.0.1),但这现在适用(Slick 2.0.1):

    使用?上面的投影,可以创建一个Slick投影来转换Optionvalues => 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后面转换为元组.

    2023-02-12 19:08 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有