Scala значение возврата скольжения

Я новичок в Scala и борется со пятном и не вижу, как вернуть результаты запроса вызывающему методу

У меня есть простой UserDto

case class UserDto(val firstName:String,
  val lastName:String,
  val userName:String,
  val isAdmin:Boolean) {}

объект таблицы пользователя

object User extends Table[(String, String, String, Boolean)]("USER") {

  def firstName = column[String]("FIRST_NAME")
  def lastName = column[String]("LAST_NAME")
  def userName = column[String]("USER_NAME")
  def admin = column[Boolean]("IS_ADMIN")

  def * = firstName ~ lastName ~ userName ~ admin

}

и класс запроса

class UserQuerySlickImpl(dataSource:DataSource) {

  def getResults(userName:String):Option[UserDto] = {
    var resultDto:Option[UserDto] = None

    Database.forDataSource(dataSource) withSession {
      val q = for {u <- User if u.userName is userName}
      yield (u.firstName, u.lastName, u.userName, u.admin)

      for (t <- q) {
        t match {
          case (f:String, l:String, u:String, a:Boolean) => 
            resultDto = Some(new UserDto(f, l, u, a))
        }
      }
    }
    resultDto
  }
}

Я могу запросить базу данных и получить пользователя, который соответствует имени пользователя, но единственный способ узнать, как вернуть этого пользователя, создав var вне Database.forDataSource....{}.

Есть ли лучший способ, который не использует var, но возвращает resultDto напрямую.

также есть способ построить UserDto непосредственно из первого для понимания, а не для второго для (t < - q)...

Я использую slick_2.10.0-M7, версия 0.11.1.

Ответы

Ответ 1

Я еще не играл с Slick, но если это разумно (под которым я подразумеваю совместимость с соглашениями Scala), вы должны иметь возможность сделать что-то вроде

def getResults(userName:String):Option[UserDto] =
  Database.forDataSource(dataSource) withSession {
    val q = for {u <- User if u.userName is userName}
      yield (u.firstName, u.lastName, u.userName, u.admin)

    q.firstOption map { case (f, l, u, a) => UserDto(f, l, u, a) }
  }

Это именно то, что вы бы сделали, если q был List[(String, String, String, Boolean)].

Устранив это немного, вы можете написать

def getResults(userName:String):Option[UserDto] =
  Database.forDataSource(dataSource) withSession {
    (for (u <- User if u.userName is userName)
      yield UserDto(u.firstName, u.lastName, u.userName, u.admin)).firstOption
  }

В противном случае вы сможете использовать

q foreach { 
   case (f, l, u, a) => return Some(UserDto(f, l, u, a))
}
return None

Как правило, следует избегать утверждений return, подобных этому, поэтому, надеюсь, тип q даст вам что-то более функциональное для работы.

Ответ 2

Ваш q - это запрос, а не список результатов. Присутствие foreach может быть немного запутанным в этом отношении, но для получения результатов List вам нужно сначала выполнить q.list. Это дает вам методы типа map и foldLeft и т.д.

Если вы хотите получить один/первый результат в Option, используйте q.firstOption. После этого вы можете map выполнить свою функцию над результирующей "Option [(...)]", чтобы преобразовать кортеж в требуемый DTO.

Альтернативным способом было бы указать настраиваемое сопоставление, которое автоматически сопоставляет ваши кортежи результатов с некоторым классом case с помощью оператора <>, см. http://slick.typesafe.com/doc/0.11.2/lifted-embedding.html#tables:

case class User(id: Option[Int], first: String, last: String) 

object Users extends Table[User]("users") {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
  def first = column[String]("first")
  def last = column[String]("last")
  def * = id.? ~ first ~ last <> (User, User.unapply _)
}