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



假设我有一个模型,如下所示:

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

那么我应该这样做吗:

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

我还应该以某种方式为每个用户类型关联一个值。

然后我会将用户案例类更改为具有 UserType 属性而不是 int?

我想然后我会为slick创建一个隐式转换器,我相信这将是从int到UserType的MappedColumnType。

更新这是为了使用光滑的数据库访问。

我会反过来做。我会根据扩展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类型进行模式匹配。

我会选择枚举:

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
)

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

更新选择枚举而不是 trait 的原因之一是,当您不显式放置超类型时,slick 无法找到此隐式转换器。例如

.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))

正如下面提到的@Michal Tomanski - 使用 trait/case object s 时存在某些问题。您需要做的是:

 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指出的。但是,您可以做一些小技巧来平滑一点。

只需像这样修改您的特征:

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

然后你可以像这样查询:

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

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

除此之外 - 我会遵循 Tomanski @Michal答案(使用 Enumeration (,假设它足以满足您的情况(也许使用 trait/case object s 的解决方案更灵活,但另一方面,您需要做更多的管道,如本答案所示(。

最新更新