How to structure the level of access to a database with transactions

I am trying to port the application to Slick 3.0. I would like to make a transaction for Slick 3.0. I know how to do this, but I would like to ask for a class structure. Please see sample repositories:

Some repositories (or DAOs) for Slick 2.1:

class UserRepository { def all()(implicit: Session): Seq[User] = users.run def insert(user: User)(implicit: Session): Int = users.insert(user) ... } class CarRepository { def all()(implicit: Session): Seq[Car] = cars.run def insert(car: Car)(implicit: Session): Int = cars.insert(car) ... } 

To complete a transaction in Slick 2.1, I could create a service in which I can complete a transaction:

 db.withTransaction{ implicit session => userRepository.insert(user) carRepository.insert(car) } 

so I currently have repositories (or DAOs) for accessing the database and services for more general logic.

Some repositories (or DAOs) for Slick 3.0:

 class UserRepository { def all(): Future[Seq[User]] = db.run(Users.result) def insert(user: User): Future[Int] = db.run(Users += user) ... } class CarRepository { def all(): Future[Seq[Car]] = db.run(Cars.result) def insert(car: Car): Future[Int] = db.run(Cars += car) ... } 

In Slick 3.0, we can execute a transaction on DBIOActions, but when we have a structure as shown above, this is not possible due to futures. I could create some UserCarRepository class to complete the transaction, but I think that it is not the best. To overcome this situation, I open DBIOActions in repositories (or DAOs), and then in another layer mix DBIOActions from user and car repositories in one transaction in order to return the future at the end (the next level may be a service for working in futures). When we have more repositories for transactions, it can get a little messy.

How to structure it for Slick 3.0? How to get a looser connection for a transaction on different repositories?

Read: https://github.com/playframework/play-slick/tree/master/samples https://github.com/slick/slick/issues/1084 https://groups.google.com/forum/#! topic / scalaquery / 32cO7lHbxOs

+5
source share
1 answer

Keep the inserts as DBIOActions for as long as possible, compose them as needed, and then execute the actual DB query. Sketch:

 class UserRepository { def all() = Users.result def insert(user: User) = Users += user ... } class CarRepository { def all() = Cars.result def insert(car: Car) = Cars += car ... } val composedInserts = (for { _ <- new UserRepository().insert(user) _ <- new CarRepository().insert(car) } yield ()).result db.run(composedInserts.transactionally) 

Edit: clarified message

+1
source

All Articles