Я использую Play-Slick версии 2.5.x и 3.1.x соответственно. Я использую генератор кода Slick и создаю модель Slick из существующей базы данных. На самом деле я стесняюсь признать, что я управляюсь DB-дизайном, а не управляем классом.Play-Slick: возможно ли улучшить этот дизайн (рисунок) ... и как его называть?
Это начальная установка:
- Сформирован Slick модель под
generated.Tables._
- реализация Generic Slick дао
- Service слой, который строит на вершине Generic Slick дао
Они являются силы, лежащие за шаблоном, который я временно называл «подключаемым сервисом», потому что он позволяет подключать функциональность уровня обслуживания к модели:
- Контроллеры и представления Playa должны видеть только Сервисный уровень (а не Дао), например.
UserService
- Сгенерированная модель, например.
UserRow
, как ожидается, будет соответствовать интерфейсам бизнес-уровня, например. Тема Deadbolt-2, но не реализует ее напрямую. Чтобы иметь возможность реализовать это, нужно «слишком много», например. тип моделиUserRow
,UserDao
и потенциально некоторый бизнес-контекст. - Некоторые из методов
UserService
естественно применимы к образцуUserRow
экземпляра, например.loggedUser.roles
илиloggedUser.changePassword
Поэтому у меня есть:
generated.Tables.scala
Slick классы модели:
case class UserRow(id: Long, username: String, firstName: String,
lastName : String, ...) extends EntityAutoInc[Long, UserRow]
dao.UserDao.scala
Dao расширения и настройки, специфичные для модели пользователя:
@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
сервис, фасадов всех пользовательских операций в остальной части приложения 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
наконец фактическое «вставные» шаблон, который динамически придает реализации услуг по типу модели:
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)
}
}
Наконец, можно сделать в контроллерах:
@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)
}
}
Есть ли способ Scala, который может помочь не писать код шаблона в объекте «Подключаемый сервис»? действительно ли имеет значение имя подключаемого сервиса?
Этот вопрос относится к http://codereview.stackexchange.com/ – Odomontois
Это вопрос дизайна, код для иллюстрации ... кроме того, активность Scala в codereview близка к несуществующей. –
Мне не хватает одной вещи здесь: почему 'findUserInSession' не может получить' User' вместе с 'role' - что-то вроде' UserWithRoles (user: UserRow, role: List [Role]) '? –