8

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.

ThaDon
  • 7,826
  • 9
  • 52
  • 84
  • You can have a transactional service with implicit session as [suggested here](http://stackoverflow.com/questions/28398482/how-we-use-slick-transaction-on-service-layer-for-making-a-transaction-system). Side note: are you sure you Repos are actually Repositories, not DAO objects? – MirMasej Jul 29 '15 at 18:15

2 Answers2

4

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.

ka4eli
  • 5,294
  • 3
  • 23
  • 43
  • I'm not sure that creating a custom *Repo class anytime a service method needs to call two repo calls within a transaction is feasible in my case. – ThaDon Jul 29 '15 at 11:46
  • @ThaDon, not creating custom but reuse one of already existing. In your example they are `SomethingRepo` or `SomethingElseRepo` – ka4eli Jul 30 '15 at 20:24
0

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.

Adrian Lopez
  • 1,776
  • 1
  • 17
  • 35