我目前有一组以约定*SlickRepo
命名的数据访问对象。例如,UserSlickRepo
,DistributionSlickRepo
,ContentSlickRepo
等......
这些Repos中的每一个都有基本符合此约定的方法:
trait SomethingRepoImpl extends SomethingRepo {
val somethingRepo: SomethingRepo = new SomethingRepoImpl
class SomethingRepoImpl extends SomethingRepo with MySlickDatastore {
def getSomething(id: UUID): Either[SomethingNotFoundError, Something] = {
getDatabase withDynSession {
// Slick stuff
}
}
def createSomething .....
}
}
现在处于服务级别,我们在这个repo类中进行烘焙,我们的方法看起来像这样:
trait SomethingServiceImpl extends SomethingService {
dep: SomethingRepo with SomethingElseRepo =>
val somethingService = new SomethingServiceImpl
class SomethingServiceImpl extends SomethingService {
def createSomethingGood(): Either[SomeError, (Something, SomethingElse)] = {
(dep.somethingRepo.createSomething, dep.somethingElseRepo.createSomethingElse)
}
}
}
我们现在希望createSomethingGood
实际运行事务中的两个repo方法。由于所有Slick内容都被锁定在Slick特定的Repo方法中,这样做的最佳方法是什么?我并不反对在我的*ServiceImpl
类中使用特定于Slick的代码(我的意思很奇怪,但确定),但是这意味着我必须更改我的Repo类以删除getDatabase withDynSession
类型代码一起,而是从服务层传递一个会话?对我而言,这似乎是错误的。
答案 0 :(得分:4)
从我的观点来看,正确的方法是将createSomething
和createSomethingElse
添加到一个*Repo
(SomethingRepo
或SomethingElseRepo
)交易方法({{ 1}})。这不是一个漂亮的解决方案,但对我来说尽可能简单,因为这些实体是逻辑连接的(我们可以从这段代码withTransaction {...}
看到))我认为在一个DAO类中混合操作2个实体并不是一个大的违规行为。如果我错了,请修理我。
答案 1 :(得分:0)
也许有另一种方式。我自己没有尝试过,但想法是你可以有一个实际传递给Repo的Session包装器。
必须在服务层创建包装器,但是您可以在配对对象上抽象特定的实现,这样服务层实际上不会处理Slick,而是像
SessionWrapper.transactional: Session
我希望这会有所帮助,如果我自己试一试,我会在回复中添加更多内容。