[英]Scala dependency injection when using case class/companion object pattern
In migrating to Play 2.5, I am adopting the dependency injection design patterns, including for (JDBC) database access. 在迁移到Play 2.5时,我采用了依赖注入设计模式,包括(JDBC)数据库访问。
At a class level, I understand the concept: 在课堂上,我理解这个概念:
class Users @Inject() (db: Database)
But I have not yet seen a discussion of how this might apply when you require database access within methods of a case class and companion object pattern. 但是,当您需要在案例类和伴随对象模式的方法中进行数据库访问时,我还没有看到有关如何应用这种情况的讨论。 An example basic model being:
一个示例基本模型是:
package models
import anorm._
import anorm.SqlParser._
import javax.inject._
import play.api.db._
import play.api.libs.functional.syntax._
import play.api.libs.json._
case class User @Inject() (db: Database) (
id: Option[Long] = None,
email: String
) {
def save = {
id.map { id => User.findById(id) } match {
case None => create
case _ => update
}
}
def create = db.withConnection { implicit conn =>
SQL(
"""INSERT INTO users (email) VALUES ({email})"""
).on(
'email -> email
).executeUpdate()
this
}
def update = ...
}
object User {
val simple = {
get[Option[Long]]("id") ~
get[String]("email") map {
case id ~ email =>
User(id, email)
}
}
def findById(id: Long) = db.withConnection { implicit conn =>
SQL("""SELECT * FROM users WHERE id = {id}""").on('id -> id).as(User.simple.singleOpt)
}
}
This changes the signature of the case class (making it unusable within val simple = { ... }
), and I can't figure out how to inject/access the db in the companion object. 这会更改case类的签名(使其在
val simple = { ... }
无法使用),我无法弄清楚如何在随播对象中注入/访问db。 Trying @Inject() var db: Database _
within the object results in a world of NullPointerExceptions that I'd like to avoid. 尝试
@Inject() var db: Database _
对象中的@Inject() var db: Database _
导致我想避免的NullPointerExceptions世界。
What is the recommended design pattern for this common use case in a world of dependency injection? 在依赖注入的世界中,这种常见用例的推荐设计模式是什么?
A common pattern is to put the database functionality in a separate class. 常见的模式是将数据库功能放在单独的类中。 In your case leave just the data with the user:
在您的情况下,只留下用户的数据:
case class User(id: Option[Long] = None, email: String)
And put the database functionality into a separate class: 并将数据库功能放入一个单独的类中:
class UserRepository @Inject()(db: Database) {
def save(user: User) = { ... }
def create() : User = { ... }
def findById(id: Long) : Option[User] = { ... }
}
Don't know how you'll be using the User
objects in your code. 不知道如何在代码中使用
User
对象。 But with that pattern you don't carry a reference to the database with every user object basically leaking the persistence implementation to wherever user objects are used. 但是使用该模式,您不会携带对数据库的引用,每个用户对象基本上将持久性实现泄露到使用用户对象的任何位置。 Maybe you want to have this but the way how you create a
User
object in val simple = ...
indicates to me that you want to create user objects just containing data. 也许你想拥有这个但是你在
val simple = ...
创建一个User
对象的方式向我表明你想要创建只包含数据的用户对象。
Now you are passing the user object around and only when database functionality is needed you inject the UserRepository
. 现在您要传递用户对象,并且只有在需要数据库功能时才注入
UserRepository
。
This doesn't exactly provide an answer to your question regarding dependency injecting into companion objects, but may be of help anyway. 这并不能完全解决您关于依赖注入伴随对象的问题,但无论如何都可能有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.