我有以下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)
}
现在,我有以下问题:
您如何处理查询而不返回给定查询的值?例如,如果表中不存在登录信息?我是以正确的方式做到的吗?或者,还有更好的方法?
我原本认为光滑在连接中自动满足Option
值,但似乎没有。为什么Option
值没有解除?
上述内容是否会被翻译成两个SQL查询和数据库调用?如果是,我该如何重新构建它以便它只发出一个带有正确连接的数据库调用?
提前致谢!
答案 0 :(得分:1)
由于您只发布了部分代码,我将尝试根据您的问题构建一个示例。
根据您的问题loginInfoRepository.findByProviderIdAndProviderKey
返回Future[LoginInfo]
,表示您已在该方法中调用db.run
。所以回答第3点:是的,因为你两次调用db.run
,它会导致数据库的两次往返。
光滑查询是可组合的,所以您可能想要做的是,使用findByProviderIdAndProviderKey
中findUserByProviderIdAndKey
的查询,而不是结果:
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%确定,将会返回一些东西(你通常不会这样)。
此查询只会访问数据库一次,并且可能会导致连接查询(您需要查看创建的语句,以确保)。