如何使用 Slick 3.0 编写可读的嵌套连接查询

How to write readable nested join queries with Slick 3.0

此代码正在创建一个查询,用于在 Web 后端检索用户的个人资料。它创建一个查询,将必要的信息组合成一个 DTO(这只是一个案例 class),随后作为 JSON.

发回
  def getProfile(userId: Long)={
    val q = for{
    ((((u,p),a),b), ba) <- filterById(userId) join
               People on (_.personId === _.id) joinLeft
               Addresses on (_._2.addressId === _.id) joinLeft
               Businesses on (_._1._2.businessId === _.id) joinLeft
               Addresses on (_._2.flatMap(_.addressId) === _.id)
    }yield(p, a, b, ba)

    db.run(q.result.headOption).map{ _.map{case(p,a,b,ba) =>
      val business = b match {
      case Some(b) => Some(dtos.Business(b.name, b.abn, b.adminFee, ba, b.id))
      case _ => None
    }

    dtos.ProfileInfo(p, a, business)
  }}
}

我已经包含了结果处理 (db.run(...)) 仅用于上下文。

我正在寻找一种更具可读性的方式来表达查询构造。

我读这篇文章的经验是“等等,什么??... on (_._1._2.flatMap(_.addressId) ....那在做什么??为什么平面图在那里而不是这里:on (_._1._2.businessId。这些实际上是直截了当的事情,但不要直接阅读。

我正在寻找一种表达方式,不需要阅读此版本所需的扣除量。我必须 "deduce" _._1._2 是什么,以及为什么它需要展平,我不必与等效的 SQL.

相关

备注:

你应该尝试这样的事情:

val q = Users join People joinLeft Addresses joinLeft Businesses joinLeft Addresses on {
  case ((((u, p), a), b), ba) => u.personId === p.id && p.addressId === a.flatMap(_.id) && p.businessId === b.flatMap(_.id) && b.flatMap(_.addressId) === ba.id
} map {
  case ((((u, p), a), b), ba) => (p, a, b, ba)
}

另一个解决方案是在不使用 for comprehension 的情况下进行连接,这样您就不必使用下划线从元组中提取值:

val q = Users join People on {
  case (u, p) => u.personId === p.id
} joinLeft Addresses on {
  case ((u, p), a) => p.addressId === a.id
} joinLeft Businesses on {
  case (((u, p), a), b) => p.businessId === b.id
} joinLeft Addresses on {
  case ((((u, p), a), b), ba) => b.flatMap(_.addressId) === ba.id
} map {
  case ((((u, p), a), b), ba) => (p, a, b, ba)
}

您没有提供数据的完整定义,因此我无法完全测试这些解决方案,但这应该能让您深入了解在 Slick 中定义连接的不同方式。让我知道这是否有帮助。