光滑的查询优化

时间:2016-06-30 10:55:23

标签: scala slick slick-3.0

我有以下Scala / Slick / PlayFramework代码:

class UserRepository @Inject()(dbConfigProvider: DatabaseConfigProvider, loginInfoRepository: LoginInfoRepository) extends BaseRepository[UserTable, User](TableQuery[UserTable], dbConfigProvider.get[JdbcProfile].db) with UserQuery {

  val db = dbConfigProvider.get[JdbcProfile].db
  def findUserByProviderIdAndKey(providerId: String, providerKey: String): Future[User] = {
    for {
      maybeLoginInfo <- loginInfoRepository.findByProviderIdAndProviderKey(providerId, providerKey)
      maybeUser <- db.run(query.filter(_.loginId === maybeLoginInfo.loginId).result.head) //query refers to the user table with a loginId column
    } yield maybeUser

  }

查询用户表和login_info表。 user表在login_info表中有一个外键。

目前,findByProviderIdAndProviderKey方法返回Future[LoginInfo]。但是,我想将其更改为为不存在的用户ID返回Future[Option[LoginInfo]]。它可以在findByProviderIdAndProviderKey方法中轻松更改,但我不确定理解的变化如何处理选项值。

我想我可能会遇到类似下面的内容(需要重构):

    class UserRepository @Inject()(dbConfigProvider: DatabaseConfigProvider, loginInfoRepository: LoginInfoRepository) extends BaseRepository[UserTable, User](TableQuery[UserTable], dbConfigProvider.get[JdbcProfile].db) with UserQuery {

      val db = dbConfigProvider.get[JdbcProfile].db
      def findUserByProviderIdAndKey(providerId: String, providerKey: String): Future[User] = {
       loginInfoRepository.findByProviderIdAndProviderKey(providerId, providerKey).map{
       case (Some(x)) => db.run(query.fitler(_.loginId == x.loginInd).result.headOption)
       case None=> Option(None)
}

现在,我有以下问题:

  1. 您如何处理查询而不返回给定查询的值?例如,如果表中不存在登录信息?我是以正确的方式做到的吗?或者,还有更好的方法?

  2. 我原本认为光滑在连接中自动满足Option值,但似乎没有。为什么Option值没有解除?

  3. 上述内容是否会被翻译成两个SQL查询和数据库调用?如果是,我该如何重新构建它以便它只发出一个带有正确连接的数据库调用?

  4. 提前致谢!

1 个答案:

答案 0 :(得分:1)

由于您只发布了部分代码,我将尝试根据您的问题构建一个示例。

根据您的问题loginInfoRepository.findByProviderIdAndProviderKey返回Future[LoginInfo],表示您已在该方法中调用db.run。所以回答第3点:是的,因为你两次调用db.run,它会导致数据库的两次往返。

光滑查询是可组合的,所以您可能想要做的是,使用findByProviderIdAndProviderKeyfindUserByProviderIdAndKey的查询,而不是结果:

def findUserByProviderIdAndKey(providerId: String, providerKey: String): Future[Option[User]] = {
    val userQuery = for {
      loginInfo <- loginInfoQuery if loginInfo.providerId === providerId && loginInfo.providerKey === providerKey
      user <- query if user.loginId === loginInfo.loginId
    } yield user

    db.run( userQuery.result.headOption )
}

for comprehension的第一行用给定的参数查询所有LoginInfos(我猜测了你的查询和字段名称)。 第二行使用给定LoginInfos的{​​{1}}和查询Users

现在如果loginId没有返回任何内容,则第二行将永远不会被执行(for comprehension的性质)和光滑将不会返回任何内容。 如果第一行返回某些内容,但没有loginInfoQuery给定User,则光滑也不会返回任何内容。 只有当两行都返回某些内容时,光滑才会实际返回值。

要从结果集中返回一个选项,请使用loginId。你永远不应该使用userQuery.result.headOption,除非你100%确定,将会返回一些东西(你通常不会这样)。

此查询只会访问数据库一次,并且可能会导致连接查询(您需要查看创建的语句,以确保)。