我是Slick的新手,这是我第一次尝试用它创建一个应用程序。
我有case class User(userID: UUID, firstName: String, lastName: String)
。
用户可以登录。
这是case class LoginInfo(providerID: String, providerKey: String)
的来源(我正在使用Silhouette进行身份验证)。
我想使用Slick User
将每个LoginInfo
与Table
相关联:
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)
。
User
和LoginInfo
的表格很简单:
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。
答案 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,因此它做的事情完全不同:)