Slick Repo methods all participating in one Service's Transaction

261 views Asked by At

I currently have a set of Data Access Objects named with the convention *SlickRepo. So for instance, UserSlickRepo, DistributionSlickRepo, ContentSlickRepo, etc...

Each of these Repos have methods on them that basically follow this convention:

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 .....
  }
}

Now up at a Service level, we bake in this repo class and we have methods that look like this:

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)
    }

  }
}

We now desire to have createSomethingGood actually run the two repo methods within a transaction. Since all the Slick stuff is locked up in the Slick specific Repo methods, what's the best way to do this? I'm not opposed to having Slick-specific code in my *ServiceImpl classes (I mean weird, but ok), however does that mean I have to change my Repo classes to remove the getDatabase withDynSession type code all together and instead pass in a session from the service layer? To me, that just seems... wrong.

2

There are 2 answers

0
Adrian Lopez On

Maybe there is another way. I haven't tried it myself, but the idea is that you could have a Session wrapper that actually gets passed to the Repo.

That wrapper would have to be created at the service layer, but you can abstract the specific implementation on a companion object so the service layer doesn't actually deal with Slick, but rather something like

SessionWrapper.transactional: Session

I hope this helps, I'll add more to the response if I get the change to give it a try myself.

2
ka4eli On

From my point of view the right approach is to add createSomething and createSomethingElse to one *Repo (SomethingRepo or SomethingElseRepo) transactional method (withTransaction {...}). It's not a beautiful solution but as simple as possible for me and because these entities are logically connected (which we can see from this code (dep.somethingRepo.createSomething, dep.somethingElseRepo.createSomethingElse)) I think it's not a big violation to mix operation on 2 entities in one DAO class. Please, fix me, if I'm wrong.