我正在使用游戏2.3和光滑的2.1
我有两个相关实体 - Message
和User
(简化示例域)。消息由用户编写。
表达此类关系的A recommended way (the only way?)是在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
- 如模板引擎和模型类我比Slick更熟悉Hibernate;在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) }
然后将其传递到任何地方。我担心的是这个额外的类 - 不是很干,所以不必要的转换(似乎我不能暗示它),很多样板。
常见方法是什么? 有没有办法减少额外的类,实际上让模型能够返回它的关联?
答案 0 :(得分:0)
根据我的评论:
在我看来,如何处理联接结果是个人品味的问题,您的方法也是我也会使用的,您有一个特殊的数据结构,可以封装您的数据并且可以轻松传递(例如在视图中)和访问。
我想到的另外两种方法是
查询字段而不是对象,它不太清晰,我通常讨厌使用元组(在这种情况下为三元组),因为我发现符号_._1
比MyClass.myField
更不清晰。这意味着做这样的事情:
val messageList = (
for (
u <- db.users;
m <- db.messages if u.id === m.userId
) yield (u.displayName, m.date, m.text))
.sortBy({ case (name, date, text) => date })
.drop(n)
.take(amount)
.list()
哪个会返回一个三元组,然后可以在你的视图中传递,这是可能的,但我永远不会这样做。
另一种选择是传递对象的元组,与你的方法非常相似,除了最后一个map
val messageList: List[(User, Message)] = (
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()
在这里你可以传递这样的观点:
@(messagesAndAuthors: List[(User, Message)])
然后使用元组和类访问功能访问数据,但同样,您的模板将是_1
的集合,再次阅读起来很糟糕,而且您必须执行messagesAndAuthors._1.name
之类的操作只是为了得到一个值。
最后,我更喜欢在我的视图中尽可能地传递变量(我猜这是计算机科学中为数不多的普遍接受的原则之一)并隐藏模型中使用的逻辑,为此使用临时案例在我看来,课程是我的选择。案例类是一个非常强大的工具,很高兴拥有它,对你而言,它可能看起来不像其他方法(比如你所谈到的Hibernate
那样干涩和冗长)但是认为当开发人员会读取你的代码时它会在这一刻变得如此简单,而且额外的小班级将节省数小时的头部撞击。
对于Session
问题,请参阅this related question,目前无法避免传递它(据我所知)但你应该能够控制这种情况并避免传递会话你的模板,我通常在我的入口点创建一个会话(大多数时候是一个控制器)并将其传递给模型。
注意:代码未经测试,可能存在一些错误。