我使用Play 2和Anorm来管理数据库访问。我发现自己正在做的一个常见模式是:
val (futureChecklists, jobsLookup) =
DB.withConnection { implicit connection =>
val futureChecklists = futureChecklistRepository.getAllHavingActiveTemplateAndNonNullNextRunDate()
val jobsLookup = futureChecklistJobRepository.getAllHavingActiveTemplateAndNonNullNextRunDate()
.groupBy(_.futureChecklist.id)
.withDefaultValue(List.empty)
(futureChecklists, jobsLookup)
}
这似乎有点奇怪,因为我必须重复自己。如果我在外部范围内需要几个变量,那么它也会变得有点不守规矩,但我不想让连接保持打开状态。
是否有一种简单的方法可以将这些信息传回去,而无需使用var
?
我想要的是:
val futureChecklists
val jobsLookup
DB.withConnection { implicit connection =>
futureChecklists = futureChecklistRepository.getAllHavingActiveTemplateAndNonNullNextRunDate()
jobsLookup = futureChecklistJobRepository.getAllHavingActiveTemplateAndNonNullNextRunDate()
.groupBy(_.futureChecklist.id)
.withDefaultValue(List.empty)
}
这样我在开始和结束时都没有相同的元组。
答案 0 :(得分:1)
恐怕没有简单的方法可以不复制元组声明,但var
绝对不是解决问题的方法。
你提到过多个变量作为一个元组返回时变得奇怪和困难。这确实会变得非常棘手并且容易出错,尤其是最终你会得到具有相同参数类型的大型N元组。在那种情况下,我会考虑使用一个专用的包含case class
,您可以在其中按名称引用变量,而不是按元组中的位置引用变量。另一个好处是,您可以将整个容器分配给变量并以自然方式引用它。
最后但并非最不重要的是,您没有提及您的特定用例,但可能值得考虑在单独的withConnection
块中获得2个查询结果。如果您正在使用任何集合池机制,那么使用连接块和单独的块几乎没有任何好处,甚至可以灵活地使用单独的连接来简化数据库查询。
答案 1 :(得分:0)
我想出了三种方法:
val (users, posts) =
DB.withConnection { connection => (
connection.getUsers,
connection.getPosts
)}
我认为这对于简单代码和少量val
来说是可以的。对于更复杂的代码和更多val
s,这可能容易出错。有人可能会在赋值的一侧意外地更改元组中元素的顺序,并将数据分配给错误的val
(仅当编译器也会导致类型不匹配时才由编译器报告)。
val dbResult =
DB.withConnection { connection =>
new {
val users = connection.getUsers
val posts = connection.getPosts
}
}
如果您想使用users
和posts
个变量代替dbResult.users
和dbResult.posts
,您可以:
import dbResult._
这个解决方案有点异国情调,但效果很好而且很干净。
首先为您的返回值定义案例类:
case class DBResult(users: List[User], posts: List[Post])
然后使用它:
val DBResult(users: List[User], posts: List[Post]) =
DB.withConnection { connection =>
DBResult(
users = connection.getUsers,
posts = connection.getPosts
)
}
如果您打算多次重复使用此案例类,这是最好的。