我正在使用带有 slick 2.1 的 play 2.3
我有两个相关的实体 -Message
和User
(一个简化的示例域)。消息由用户编写。
表达这种关系的推荐方式(唯一的方式?)是使用显userId
式Message
我的类和表映射如下所示:
case class Message (
text: String,
userId: Int,
date: Timestamp = new Timestamp(new Date().getTime()),
id: Option[Int] = None) {}
case class User (
userName: String,
displayName: String,
passHash: String,
creationDate: Timestamp = new Timestamp(new Date().getTime()),
lastVisitDate: Option[Timestamp] = None,
// etc
id: Option[Int] = None){}
class MessageTable(tag: Tag) extends Table[Message](tag, "messages") {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
def text = column[String]("text")
def userId = column[Int]("user_id")
def date = column[Timestamp]("creation_date")
def * = (title, text, userId, date, id.?) <> (Post.tupled, Post.unapply
def author = foreignKey("message_user_fk", userId, TableQuery[UserTable])(_.id)
}
class UserTable(tag: Tag) extends Table[User](tag, "USER") {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
def username = column[String]("username")
def passHash = column[String]("password")
def displayname = column[String]("display_name")
def * = (username, passHash,created, lastvisit, ..., id.?) <> (User.tupled, User.unapply)
}
还有一个方便的辅助对象:
object db {
object users extends TableQuery(new UserTable(_)) {
// helper methods, compiled queries
}
object messages extends TableQuery(new MessageTable(_)) {
// helper methods, compiled queries
}
}
现在,这在内部是完美的,但是如果我想显示实际的消息,我希望消息类在模板中使用时能够返回它的作者姓名。
以下是我的考虑:
- 我不想(而且我无论如何也不能)
Session
在它不属于的地方传递隐式光滑 - 比如模板引擎和模型类 - 在这种特殊情况下,我想避免一一请求消息的附加数据
我对 Hibernate 比对 Slick 更熟悉;在 Hibernate 中,我会使用 join-fetching。对于 Slick,我想出的最佳想法是使用另一个数据保持器类进行显示:
class LoadedMessage (user:User, message:Message) {
// getters
def text = message.text
def date = message.date
def author = user.displayName
}
object LoadedMessage {
def apply( u:User , m:Message ) = new LoadedMessage(u, m)
}
并用连接查询的结果填充它:
val messageList: List[LoadedMessage] = (
for (
u <- db.users;
m <- db.messages if u.id === m.userId
) yield (u, m))
.sortBy({ case (u, m) => m.date })
.drop(n)
.take(amount)
.list.map { case (u, m) => LoadedMessage(u, m) }
然后将它传递到任何地方。我关心的是这个额外的类——不是很干,所以不必要的转换(而且似乎我不能让它隐含),很多样板。
常见的做法是什么?有没有办法减少额外的类并实际上使模型能够返回它的关联?