firstOption показывает ошибку в slick 3.0 и play 2.4

Я интегрирую силуэт (ветвь securesocial) в свой проект в качестве библиотеки аутентификации, поэтому я следую его примеру проекта с slick play-silhouette-slick-seed.

При написании эти строки Я получаю много ошибок в eclipse.

def find(loginInfo: LoginInfo) = {
  DB withSession { implicit session =>
    Future.successful {
      slickLoginInfos.filter(
        x => x.providerID === loginInfo.providerID && x.providerKey === loginInfo.providerKey
      ).firstOption match {
        case Some(info) =>
          slickUserLoginInfos.filter(_.loginInfoId === info.id).firstOption match {
            case Some(userLoginInfo) =>
              slickUsers.filter(_.id === userLoginInfo.userID).firstOption match {
                case Some(user) =>
                  Some(User(UUID.fromString(user.userID), loginInfo, user.firstName, user.lastName, user.fullName, user.email, user.avatarURL))
                case None => None
              }
            case None => None
          }
        case None => None
      }
    }
  }
}

[Ожидаются ошибки, так как пример проекта написан с использованием старых версий play и slick]

Я попытался перенести их, поэтому заменил withSession на run и firstOption на headOption, так как я прочитал в гладком официальном документе, что прежние устарели в slick 3.0. Ниже приведены мои изменения, но они все еще не работают.

def find(loginInfo: LoginInfo) = {
   DB run { 
     Future.successful {
        slickLoginInfos.filter(
          x => x.providerID === loginInfo.providerID && x.providerKey === loginInfo.providerKey
        ).result.headOption match {
          case Some(info) =>
            slickUserLoginInfos.filter(_.loginInfoId === info.id).result.headOption match {
              case Some(userLoginInfo) =>
                slickUsers.filter(_.id === userLoginInfo.userID).result.headOption match {
                  case Some(user) =>
                    Some(User(UUID.fromString(user.userID), loginInfo, user.firstName, user.lastName, user.fullName, user.email, user.avatarURL))
                  case None => None
                }
              case None => None
            }
          case None => None
        }
     }
  }
}

Я новичок в игре и scala, каждый день изучаю новые вещи. Не могли бы вы помочь мне в исправлении этих ошибок. Было бы неплохо, если бы кто-нибудь также объяснил мне использование будущих значений, чем они отличаются от обычных значений, которые мы получаем с помощью Await (db.run(....)), и как анализировать value внутри будущего объекта, так как я видел, что в некоторых местах они используют карту, а в некоторых местах они используют onSuccess или case, это довольно запутанно. Как лучше всего работать с будущими ценностями?


person Vinay    schedule 23.06.2015    source источник


Ответы (1)


Найдите joinLeft, который будет использовать Option для правого (joinRight для левого), если ничего не совпадает. Итак, вам нужно что-то вроде:

val q1 = for {
  (loginInfo, userLoginInfo) <- slickLoginInfos.filter(...) joinLeft slickUserLoginInfos on (_.id === _.loginInfoId)
} yield (loginInfo, userLoginInfo)
val q2 = for {
  ((loginInfo, userLoginInfo), user) <- q1 joinLeft slickUsers.filter(...) on (_._2.loginInfoId === _.id)
} yield {
   // use loginInfo, userLoginInfo and user are optional
}

userLoginInfo и user там будет Option либо Some, либо None в зависимости от того, было ли совпадение. Вы запускаете это q2 и headOption на нем для общего результата.

фьючерсы

Раньше вы бы сделали что-то вроде:

dao.fetch().map(_.toString)

где dao.fetch() возвращает Seq[Int]. Теперь, с Slick 3.0, это будет Future[Seq[Int]], что означает, что вам просто нужен еще один .map (или flatMap):

dao.fetch().map(_.map(_.toString))

который продолжает делать то же самое, что и раньше, за исключением того, что теперь он заключен в файл Future. Преимущество использования Futures заключается в том, что вам не нужно блокировать поток для каждого обращения к базе данных.

person bjfletcher    schedule 23.06.2015
comment
Разве мы не можем сделать это без использования объединений? Также в запросе q2 мне немного непонятно, что писать внутри slickUsers.filter(.....) - person Vinay; 28.06.2015
comment
В этом случае вам нужно будет каждый раз выполнять db.run() (просто .result этого не сделает, если вы не присоединитесь). Недостатком этого является то, что вы будете делать три отдельных вызова БД, тогда как при объединении вы будете делать только один вызов БД. - person bjfletcher; 28.06.2015
comment
Спасибо, я понял, что это будет медленно. Но не могли бы вы помочь мне в завершении второго запроса. Я просто застрял здесь, так как _._2 - это тип параметра, в котором я не могу применить оператор ===. Я учусь пятно не знаю много об этом. - person Vinay; 28.06.2015