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