【问题标题】:How can I omit case class fields in a slick table mapping?如何在光滑表映射中省略案例类字段?
【发布时间】:2016-01-30 01:04:13
【问题描述】:

我正在自学一些 Scala 并且目前正在使用 slick (3.1) + play 框架弄湿我的脚,所以这里的答案可能很简单,我错过了一些明显的东西。我有以下模型和表格

case class User(id: Long = -1,
                username: String,
                passwordHash: String,
                email: Option[String] = None) 

class Users(tag: Tag) extends Table[User](tag, "USERS") {
    def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
    def username = column[String]("USERNAME")
    def email = column[Option[String]]("EMAIL")
    def passwordHash = column[String]("PASSWD_HASH")
    def * = (id, username, passwordHash, email) <>((User.apply _).tupled, User.unapply)
  }

现在上面的工作正常,但我想向User case 类添加一些字段没有保存在 USER 表中,即权限和角色,像这样:

case class User(id: Long = -1,
                username: String,
                passwordHash: String,
                email: Option[String] = None,
                permissions: Seq[String] = Seq.empty,
                roles: Seq[String] = Seq.empty) 

这些应该以用户 ID -> 权限/角色映射(简单的一对多关系)进入各自的表。

最终,这些也应该被查询,但现在我只想忽略其他字段(纯粹作为练习)。如何调整表格中的原始投影以忽略/忽略那些新字段?显然是原始映射

 def * = (id, username, passwordHash, email) <>((User.apply _).tupled, User.unapply)

不再起作用,因为 touple 与 case 类不匹配。据我所知,这不应该太难,因为&lt;&gt; 只需要两个函数,从一个 touple 转换为一个 User 实例,反之亦然,这些函数应该忽略新字段(或用它们的默认值填充它们)。但我不知道如何表达。

我尝试向User 伴随对象添加一个具有更短签名的新apply(),但随后我收到一个错误,基本上告诉我slick 不知道要使用哪个apply()。有道理,但我不知道如何引用其中一个。我为User 使用了一个额外的构造函数做了同样的事情,结果是同样的问题。我尝试编写这样的基本转换函数:

class Users(tag: Tag) extends Table[User](tag, "USERS") {

    def constructUser = (id: Long, username: String, passwordHash: String, email: Option[String]) =>
      User(id, username, passwordHash, email)

    def extractUser = (user: User) => user match {
      case User(id, username, passwordHash, email, permissions, roles) =>
        Some((id, username, passwordHash, email))
    }

    def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
    def username = column[String]("USERNAME")
    def email = column[Option[String]]("EMAIL")
    def passwordHash = column[String]("PASSWD_HASH")
    def * = (id, username, passwordHash, email) <>(constructUser, extractUser)
  }

不幸的是,这也会导致错误:

[error]  found   : (Long, String, String, Option[String]) => models.User
[error]  required: ? => ?
[error]     def * = (id, username, passwordHash, email) <>(constructUser, deconstructUser)

【问题讨论】:

    标签: scala jdbc playframework slick slick-3.0


    【解决方案1】:

    你的问题是你的constructUser是4个参数的函数,而它应该是单个Tuple4的函数

    尝试添加类型签名。
    例如,此示例有效(包括一些简化)

    type Data = (Long, String, String, Option[String])
    
    def constructUser: Data => User = {
      case (id, username, passwordHash, email) => User(id, username, passwordHash, email)
    
    }
    def extractUser: PartialFunction[User, Data] = {
      case User(id, username, passwordHash, email, _, _) =>
        (id, username, passwordHash, email)
    }
    
    def * = (id, username, passwordHash, email) <> (constructUser, extractUser.lift)
    

    【讨论】:

    • 这很有效,而且非常有意义。谢谢你。遗憾的是我还不能投票。 :)
    • @Odomontois 谢谢。在上述情况下,答案也适用于我(即 - 将一些字段添加到未保存在 USER 表中的用户案例类)。但就我而言(例如),我已将另一个表添加为 USER 表中的字段。我添加了“accessToken:Option [AccessToken] = None”和“oauthClient:Option [Client] = None”,而不是“权限,角色”。但我想映射这些值。我该怎么做?您能否检查以下问题 - stackoverflow.com/q/37183156/1584121
    • @Odomontois,谢谢,这很有帮助!我只是想补充一点,这个策略(好吧,你必须稍微改变一下这段代码)可以用来消除案例类和表之间的不匹配(这就是我所做的):如果你的案例类字段数少于表中的行数(例如,如果您的案例类中没有 id)。我用谷歌搜索的所有其他技术都更难。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 1970-01-01
    • 2021-01-23
    • 2013-04-11
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多