2016-06-30 5 views
1

나는 다음과 같은 스칼라/슬릭/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 쿼리와 데이터베이스 호출로 변환 할 수 있습니까? 그렇다면 올바른 구조로 데이터베이스 호출을 하나만 발행하도록 구조를 어떻게 다시 구성합니까?

미리 감사드립니다.

+0

당신의 질문이 당신의'findByProviderIdAndProviderKey' 메소드에 관한 것이므로, 이것을위한 코드를 게시 할 수 있습니까? – thwiegan

답변

1

코드의 일부만 게시 했으므로 귀하의 질문에 기반한 예제를 만들려고합니다.

질문에 따르면 loginInfoRepository.findByProviderIdAndProviderKeyFuture[LoginInfo]을 반환합니다. 즉, 이미 해당 방법에서 db.run으로 전화했음을 의미합니다. 따라서 포인트 3에 응답하려면 : 예, db.run을 두 번 호출하기 때문에 데이터베이스로 왕복 2 회 왕래합니다.

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

이해의 첫 번째 라인은 주어진 모든 LoginInfos를 쿼리 :

슬릭 타이어 쿼리는 아마 당신은 결과를,이다 할 findUserByProviderIdAndKeyfindByProviderIdAndProviderKey의 쿼리를 사용하지하고자 그래서 뭐, 작성 가능하다 매개 변수 (나는 귀하의 쿼리 및 필드 이름을 짐작). 두 번째 줄은 LoginInfos이고, Users은 주어진 loginId입니다.

이제 loginInfoQuery이 아무 것도 반환하지 않으면 두 번째 줄은 절대로 실행되지 않으며 이해를 돕기 위해 아무 것도 반환하지 않습니다. 첫 번째 행에서 무언가가 반환되지만 User이없고 지정된 loginId이 있으면 slick도 아무 것도 반환하지 않습니다. 두 줄이 모두 반환되면 slick은 실제로 값을 반환합니다.

결과 집합에서 하나의 옵션을 반환하려면 userQuery.result.headOption을 사용하십시오.userQuery.result.head을 100 % 확신하지 않는 한 절대 사용하지 말아야하며, 무엇인가가 반환 될 것입니다 (일반적으로 불가능합니다).

이 쿼리는 데이터베이스에 한 번만 도달하므로 조인 된 쿼리가 생성됩니다 (작성된 문을 확인해야합니다).

+0

감사합니다. 나 자신에게 몇 가지 일을 시도한 후에 같은 해결책을 찾았지만 대답에 감사드립니다. 그것은 내가 실제로 무엇을 찾고 있었는지입니다. – MojoJojo

+0

답변을 수락 하시겠습니까? :) – thwiegan

+1

사과 .. 나는 대답을 upvoted지만 그것을 받아들이는 것을 잊었습니다. 지금 그것을 받아 들였습니다 :-) – MojoJojo