参考化合物主键

时间:2016-01-16 11:13:45

标签: scala slick slick-3.0

我是Slick的新手,这是我第一次尝试用它创建一个应用程序。

我有case class User(userID: UUID, firstName: String, lastName: String)

用户可以登录。 这是case class LoginInfo(providerID: String, providerKey: String)的来源(我正在使用Silhouette进行身份验证)。

我想使用Slick User将每个LoginInfoTable相关联:

class UsersWithLoginInfos(tag:Tag) extends Table[(PrimaryKey, UUID)](tag, "USERS_WITH_LOGIN_INFOS"){
  def loginInfoID = TableQuery[LoginInfos].shaped.value.loginInfoID
  def userID = column[UUID]("USER_ID")
  def * = (loginInfoID, userID) <>(UserWithLoginInfo.tupled, UserWithLoginInfo.unapply)
}

这是相应的case class UserWithLoginInfo(loginInfoID: PrimaryKey, userID: UUID)

UserLoginInfo的表格很简单:

class LoginInfos(tag: Tag) extends Table[LoginInfo](tag, "LOGIN_INFOS") {

  // The primary key of this table is compound: it consists of the provider's ID and its key
  def loginInfoID = primaryKey("LOGIN_INFO_ID", (providerID, providerKey))

  // "credentials" for example
  def providerID = column[String]("PROVIDER_ID")

  // "admin@nowhere.com" for example
  def providerKey = column[String]("PROVIDER_KEY")

  def * = (providerID, providerKey) <>(LoginInfo.tupled, LoginInfo.unapply)
}
class Users(tag: Tag) extends Table[User](tag, "USERS") {

  def id = column[UUID]("ID", O.PrimaryKey)

  def firstName = column[String]("FIRST_NAME")

  def lastName = column[String]("LAST_NAME")

  def * = (id, firstName, lastName) <>(User.tupled, User.unapply)
}

不幸的是,这不是类似的问题:

def * = (loginInfoID, userID) <>(UserWithLoginInfo.tupled, UserWithLoginInfo.unapply)
  

MappedProjection类型的表达式[UserWithLoginInfo,(PrimaryKey,   UUID)]不符合预期类型ProvenShape [(PrimaryKey,   UUID)]

我可以通过引入case class LoginInfoWithID(info: LoginInfo, id: UUID)来解决这个问题,但我希望能够直接引用LoginInfo的复合主键。

有办法做到这一点吗?或者我完全走错了轨道?

我正在使用Slick 3.0.0。

1 个答案:

答案 0 :(得分:0)

我不太确定你要在这里实现什么,但如果只是为了获得User及其关联的LoginfInfo(未经测试的代码):

class LoginInfos(tag: Tag) extends Table[LoginInfo](tag, "LOGIN_INFOS") {
  def providerID = column[String]("PROVIDER_ID")
  def providerKey = column[String]("PROVIDER_KEY")

  def * = (providerID, providerKey) <>(LoginInfo.tupled, LoginInfo.unapply)
  def pk = primaryKey("PK_LOGIN_INFO_ID", (providerID, providerKey))
}

class Users(tag: Tag) extends Table[User](tag, "USERS") {
  def id = column[UUID]("ID", O.PrimaryKey)
  def firstName = column[String]("FIRST_NAME")
  def lastName = column[String]("LAST_NAME")

  def * = (id, firstName, lastName) <>(User.tupled, User.unapply)
}

class UsersWithLoginInfos(tag:Tag) extends Table[(providerID: String, providerKey: String, UUID: String)](tag, "USERS_WITH_LOGIN_INFOS"){
  def providerID = column[String]("USER_PROVIDER_ID")   //  column name assumption
  def providerKey = column[String]("USER_PROVIDER_KEY") //  column name assumption
  def userID = column[UUID]("USER_ID")

  def pk = primaryKey("PK_USER_WITH_LOGIN_INFO_ID", (providerID, providerKey))
}


case class UserWithLoginInfo(user: User, loginInfo: LoginInfo)

如果您愿意,可以选择将Tuple3 UsersWithLoginInfos包装在案例类中。但是,这是一个示例查询,可以User加入LoginInfo

def findUserWithLoginInfo(providerID: String, providerKey: String): Future[Option[UserWithLoginInfo]] = {
  val query = (for {
    user <- TableQuery[Users] if user.providerID === providerID && user.providerKey === providerKey
    userToLoginInfo <- TableQuery[UsersWithLoginInfos] if userToLoginInfo.userID === user.id
    loginInfo <- TableQuery[LoginInfos] if userToLoginInfo.providerID === loginInfo.providerID && userToLoginInfo.providerID === loginInfo.providerKey
  } yield UserWithLoginInfo(user, loginInfo))

  db.run(query.result.headOption)
}

您可以定义外键约束,而不是像上面那样编写一个相当详细的查询,Slick documentation, Constraints

当我开始使用光滑时,我发现Coming from ORM to Slick非常有用。请记住,光滑不是一个ORM,因此它做的事情完全不同:)