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

Gre*_*ade 3 scala slick slick-3.0

此代码创建一个查询,用于在Web后端检索用户的配置文件.它创建一个查询,将必要的信息组装到DTO(这只是一个案例类)中,随后作为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)
  }}
}
Run Code Online (Sandbox Code Playgroud)

我已将结果处理(db.run(...))仅包含在上下文中.

我正在寻找一种更易读的方式来表达查询结构.

我阅读这篇文章的经历是"等等,是什么?...... on (_._1._2.flatMap(_.addressId)那是做什么的?为什么要在那里进行平面图而不是在这里:on (_._1._2.businessId.这些实际上是直接的东西,但是不要直接阅读.

我正在寻找一种表达方式,不需要阅读此版本所需的扣除额.我必须"推断"_._ 1._2是什么,以及它为什么需要被展平,我不需要使用等效的SQL.

笔记:

  • 此代码来自我正在扩展的现有应用程序(不是我编写的).
  • 用户,人员,地址,企业(显然是?)表.
  • 人和企业都有地址.
  • 用户有人(*),人有业务
  • filterByUserId(userId)基本相当于Users.filter(_.id === userId)
  • 等效的SQL是:

    select p.*, a1.*, b.*, a2.* from Users u 
    innerJoin People p on (u.personId == p.id) 
    leftJoin Addresses a1 on (p.addressId == a1.id) 
    leftJoin Businesses b on (p.businessId == b.id) 
    leftJoin Addresses a2 on ( b.addressId == a2.id)
    
    Run Code Online (Sandbox Code Playgroud)

Paw*_*nko 5

你应该尝试这样的事情:

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)
}
Run Code Online (Sandbox Code Playgroud)

另一个解决方案是在不使用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)
}
Run Code Online (Sandbox Code Playgroud)

您尚未提供数据的完整定义,因此我无法完全测试这些解决方案,但这可以让您深入了解在Slick中定义连接的不同方法.如果这对我有帮助,请告诉我.