我应该创建特征来表示模型的枚举值吗?

时间:2017-02-13 13:00:06

标签: scala slick

说我有一个类似的模型:

case class User(
 id: Int,
 name: String,
 userType: Int)

我应该这样做:

sealed trait UserType
case object Member() extends UserType
case object Anonymous() extends UserType

我还应该以某种方式为每个UserType关联一个值。

然后我会将User case类更改为具有UserType属性而不是int?

我想我会为光滑创建一个隐式转换器,我相信它是从int到UserType的MappedColumnType。

更新的 这是为了使用灵活的数据库访问。

3 个答案:

答案 0 :(得分:2)

我会反过来做。我会为用户提供一种类型,具体取决于扩展User的场景:

sealed trait User
case class NormalUser(name: String, id: Int) extends User
case class SuperUser(name: String, id: Int, superPowers: Map[String, String]) extends User

然后在需要时对实际User类型进行模式匹配。

答案 1 :(得分:2)

我和enum一起去了:

object UserType extends Enumeration {
  type UserType = Value

  val Member = Value("Member")
  val Anonymous = Value("Anonymous")
}

转换器如你所说:

implicit val userTypeColumnType = MappedColumnType.base[UserType, String](
  userType => userType.toString,
  UserType.withName
)

然后,您可以在userType: UserType案例类中使用User。 在表格定义中,您可以拥有def userType = column[UserType]("user_type")

<强>更新 选择enum over trait的原因之一是当你没有明确地输入超类型时,光滑无法找到这个隐式转换器。 E.g。

.filter(_.userType === Member)

产量

type mismatch;
[error]  found   : Member.type
[error]  required: slick.lifted.Rep[?]
[error]       .filter(_.userType === Member).result

但以下作品

.filter(_.userType === Member.asInstanceOf[UserType])

.filter(_.userType === (Member : UserType))

答案 2 :(得分:1)

正如@Michal Tomanski所提到的below - 使用trait / case object时存在一些问题。你需要做的是:

 sealed trait UserType {
    val code: Int
  }
  case object Member extends UserType {
    override val code: Int = 0
  }
  case object Anonymous extends UserType {
    override val code: Int = 1
  }

  object UserType {
    def byId(id: Int): UserType = id match {
      case Member.code => Member
      case Anonymous.code => Anonymous
      case _ => throw new IllegalArgumentException("...")
    }
  }

  implicit val enumColumnType = MappedColumnType.base[UserType, Int](
    e => e.code,
    i => UserType.byId(i)
  )

上面会允许你这样查询:

    UserTable
      .filter(_.userType === (Member :: UserType))
      .result

这正是@Michal Tomanski所指出的。你可以做一些小技巧,但要稍微平滑一下。

只需修改你的特征:

  sealed trait UserType {
    val code: Int
    // I added field below
    val base: UserType = this
  }

然后您可以像这样查询:

   UserTable
      .filter(_.userType === Member.base)
      .result

它可能比铸造稍微好一点。

除此之外 - 我跟随@Michal Tomanski回答(使用Enumeration),假设它足以满足您的需求(可能是trait / case object s的解决方案更灵活,但另一方面,你需要做更多的管道工程,这可以在这个答案中看到。)