J'utilise les versions Play-Slick 2.5.x et 3.1.x respectivement. J'utilise le générateur de code de Slick et produis le modèle Slick à partir d'une base de données existante. En fait, je suis timide d'admettre que je suis axé sur la conception DB et non sur la conception de classe.Play-Slick: Est-il possible d'améliorer cette conception (modèle) ... et comment l'appeler?
Ceci est la configuration initiale:
- modèle généré Slick sous
generated.Tables._
- application générique Slick dao
- couche de service qui construit sur le dessus des marées noires Générique dao
Ce sont les forces derrière le modèle que j'ai temporairement appelé "Pluggable Service" parce qu'il permet de brancher la fonctionnalité de la couche de service au modèle:
- Les contrôleurs de lecture et les vues doivent uniquement voir la couche Service (et non les Dao), par ex.
UserService
- Modèle généré par ex.
UserRow
devrait être conforme aux interfaces de couche de gestion, par ex. Deadbolt-2's Subject mais ne l'implémente pas directement. Pour pouvoir l'implémenter, il faut "trop", par ex. le type de modèleUserRow
, leUserDao
et éventuellement un contexte métier. - Certaines des méthodes
UserService
s'appliquent naturellement à l'instance modèleUserRow
, par ex.loggedUser.roles
ouloggedUser.changePassword
pourquoi je:
generated.Tables.scala
classes de modèle Slick:
case class UserRow(id: Long, username: String, firstName: String,
lastName : String, ...) extends EntityAutoInc[Long, UserRow]
dao.UserDao.scala
extensions Dao et personnalisations spécifiques au modèle de l'utilisateur:
@Singleton
class UserDao @Inject()(protected val dbConfigProvider: DatabaseConfigProvider)
extends GenericDaoAutoIncImpl[User, UserRow, Long] (dbConfigProvider, User) {
//------------------------------------------------------------------------
def roles(user: UserRow) : Future[Seq[Role]] = {
val action = (for {
role <- SecurityRole
userRole <- UserSecurityRole if role.id === userRole.securityRoleId
user <- User if userRole.userId === user.id
} yield role).result
db.run(action)
}
}
services.UserService.scala
service façades toutes les opérations de l'utilisateur au reste de l'application Play:
@Singleton
class UserService @Inject()(auth : PlayAuthenticate, userDao: UserDao) {
// implicitly executes a DBIO and waits indefinitely for
// the Future to complete
import utils.DbExecutionUtils._
//------------------------------------------------------------------------
// Deadbolt-2 Subject implementation expects a List[Role] type
def roles(user: UserRow) : List[Role] = {
val roles = userDao.roles(user)
roles.toList
}
}
services.PluggableUserService.scala
enfin le modèle "Pluggable" réelle qui se fixe de façon dynamique les implémentations de service au type de modèle:
trait PluggableUserService extends be.objectify.deadbolt.scala.models.Subject {
override def roles: List[Role]
}
object PluggableUserService {
implicit class toPluggable(user: UserRow)(implicit userService: UserService)
extends PluggableUserService {
//------------------------------------------------------------------------
override def roles: List[Role] = {
userService.roles(user)
}
}
Enfin on peut faire dans les contrôleurs:
@Singleton
class Application @Inject() (implicit
val messagesApi: MessagesApi,
session: Session,
deadbolt: DeadboltActions,
userService: UserService) extends Controller with I18nSupport {
import services.PluggableUserService._
def index = deadbolt.WithAuthRequest()() { implicit request =>
Future {
val user: UserRow = userService.findUserInSession(session)
// auto-magically plugs the service to the model
val roles = user.roles
// ...
Ok(views.html.index)
}
}
Existe-t-il un moyen Scala qui pourrait aider à ne pas avoir à écrire le code standard dans l'objet Service Pluggable? le nom du service Pluggable est-il logique?
Cette question appartient à http://codereview.stackexchange.com/ – Odomontois
Il s'agit d'une question de conception, le code est à titre d'exemple ... en plus de l'activité Scala de codereview est proche de inexistant. –
Il me manque une chose ici: pourquoi 'findUserInSession' ne peut pas récupérer' User' avec 'roles' - quelque chose comme' UserWithRoles (user: UserRow, roles: List [Rôle]) '? –