3

I would like to implement utility function/monad/aspect for managing hibernate transactions in scala, and looking for advice about best approach.

First I tried to create currying function like following:

def session() = sessionFactory.getCurrentSession()

def transaction() = session().getTransaction()

def tx[A, B](f: A => B)(a: A): B = {
try {
  session().beginTransaction()
  val r = f(a)
  transaction().commit()
  return r
} catch {
  case e: 
    Throwable => 
      transaction().rollback()
      throw e
} finally {
  session.close()      
}

}

The idea was that I can do following with this function:

def saveMyEntity() {
  session().save(new MyEntity)
}

tx(saveMyEntity)()

and saveMyEntity call will be wrapped into transaction.

Unfortunately I get following error with this code:

[error]  found   : () => Unit
[error]  required: ? => ?
[error]   tx(saveMyEntity)()

I still learning scala, and looking for advice to improve my approach. Maybe I can modify my function somehow to achieve better results? Or add another Unit type specific function? Or choose another path?

Any ideas? Any scala canonical way to implement this? Thanks.

crypto5
  • 851
  • 2
  • 10
  • 16

2 Answers2

3

Method tx accepts function of 1 argument as parameter and method saveMyEntity accepts no arguments, so you can't use it as A => B (function of 1 argument).

You are not using a and f separately, so there is no need in a. You could use by-name parameters here:

def tx[B](f: => B): B = {

If you want to use a saveMyEntity as Unit => Unit you should create function explicitly:

tx[Unit, Unit](_ => saveMyEntity)(())

I guess some changes may improve your code readability:

import util.control.Exception.allCatch

def withSession[T](f: Session => T):T = {
  val session = ??? // start session here
  allCatch.anfFinally{
    session.close()
  } apply { f(session) }
}

def inTransaction[T](f: => T): T =
  withSession{ session =>
    session().beginTransaction()
    try {
      val r = f(a)
      transaction().commit()
      r
    } catch {
      case e: Throwable => 
        transaction().rollback()
        throw e
    }
  }

inTransaction{saveMyEntity}
Community
  • 1
  • 1
senia
  • 37,745
  • 4
  • 88
  • 129
  • @crypto5: `Unit` is the regular type in scala. You can define method as `saveMyEntity(u: Unit)`. It useless, but it will fix compilation. – senia Jul 08 '13 at 06:58
0
object TestTransaction
{
  def executeInTransaction(f: => Unit)={
    println("begin")
    f
    println("end")
  }
  executeInTransaction {
    println("action!")
  }
}

produces:

  begin
  action!
  end
jhegedus
  • 20,244
  • 16
  • 99
  • 167