【问题标题】:scala slick query return valuescala slick 查询返回值
【发布时间】:2012-10-17 08:13:37
【问题描述】:

我是 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
  }
}

我可以查询数据库并获取与用户名匹配的用户,但我可以弄清楚如何返回该用户的唯一方法是在 Database.forDataSource....{} 之外创建一个 var。

有没有更好的方法,不使用var而是直接返回resultDto

还有一种方法可以直接从第一个构造 UserDto 以进行理解,而不需要第二个 for (t

我使用的是 slick_2.10.0-M7,版本 0.11.1。

【问题讨论】:

标签: scala slick


【解决方案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) }
  }

如果qList[(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 的类型能够为您提供更实用的功能。

【讨论】:

  • 感谢您的快速响应,事实证明,val q 没有 head 或 headOption 方法,但支持 foreach。这意味着我可以用 q foreach { case (....) => resultDto = Some(UserDto( ... ) 替换第二个 for comprehension 更简洁,并且很好地回答了第二个问题
  • 我仍然不清楚如何将 resultDto 从第一个 Database.forDataSource(dataSource) withSession { ... } 块中取出,而不必求助于在阻止
  • withSession 方法接受一个函数参数并返回调用该函数的结果,所以您需要做的就是确保withSession 块的值(即块中的最后一个表达式)是您要返回的 Option[UserDto]。我会在我的回答中澄清代码。
  • 向@eriksensei 致敬firstOption 而不是headOption,尽管我还没有检查API 进行验证。
  • Some 是关键!
【解决方案2】:

您的q 是一个查询,而不是结果列表。在这方面foreach 的存在可能有点令人困惑,但要获得List 的结果,您需要先执行q.list。这为您提供了 mapfoldLeft 等方法。

如果您想在Option 中获得单个/第一个结果,请使用q.firstOption。一旦你有了它,你可以map你的函数在结果 'Option[(...)]` 上将元组转换为所需的 DTO。

另一种方法是指定一个自定义映射,该映射使用&lt;&gt; 运算符自动将您的结果元组映射到某个案例类,请参阅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 _)
}

【讨论】:

  • +1 很好的答案 - 你在哪里找到这个文档,即。首先,第一个选项等?我无法在 Scala Doc 或其他任何地方找到它。
  • 谢谢。 :) 文档对我来说有点拼凑。我通过查看我链接的文档、邮件列表、StackOverflow 和github.com/slick/slick-examples 拼凑出一些东西。 firstOption 来自于在源代码中四处寻找。查看 ScalaQuery 的东西(例如 GitHub 上使用它的项目)也有帮助。然后是this ebook by Adam Mackler,看起来很有用。
猜你喜欢
  • 2012-12-21
  • 1970-01-01
  • 1970-01-01
  • 2017-04-06
  • 1970-01-01
  • 1970-01-01
  • 2021-03-20
  • 1970-01-01
  • 2021-01-02
相关资源
最近更新 更多