implicit session problem

472 views
Skip to first unread message

Bandar Bandirsen

unread,
Mar 21, 2013, 9:04:21 PM3/21/13
to scala...@googlegroups.com
Hi,

I got problem when trying to create a generic dao class, which will be implemented using slick, hibernate, etc

trait AbstractDAO{
  def savePerson(id: String, name: String): Unit 
  def findPerson(n: Name): List[(String, String)] // I dont put implicit session parameter here, since other implementation, say HibernateDAO, wont need it
}

//
object SlickDAOImplementation extends AbstractDAO {
  object PersonTable extends Table[(String, String)]("person") {
    def personId = column[String]("id", O.NotNull)
    def name = column[String]("name", O.NotNull)
    def baseProjection = personId ~ name
    def * = baseProjection
    val findByName = createFinderBy(_.name)
  }

  // work ok if method return value is a Unit
  def savePerson(id: String, name: String): Unit = {
    implicit s: Session =>
      PersonTable.insert(id, name)
  }

  // problem if return value is other than Unit

  // if i do this, i get implicit value not found error
  def findPerson(n: String): List[(String, String)] = PersonTable.findByName(n) 
 
  // if i do this, then i got error since it has different signature from findPerson method in AbstractDAO
 def findPerson(n: String)(implicit s: Session): List[(String, String)]  =  PersonTable.findByName(n)              
}


somewhere in my code

val db = // get db
val personDAO: AbstractDAO = SlickDAOImplementation  // could be HibernateDAO, or etc


// I want to do insert+find inside one session/transaction
db.withSession {
  implicit s: Session =>
       s.withTransaction {
         personDAO.savePerson("first", "a name")
         personDAO.findByName("a name")
      }   
}

is there any suggestion to avoid this problem ?

Christopher Vogt

unread,
Mar 22, 2013, 11:03:54 AM3/22/13
to scala...@googlegroups.com
Abstracting over Slick and Hibernate is probably not a good idea, as they follow very different strategies. Hibernate is very mutable and object-oriented, Slick is state-less and functional. Also Slick gains its power from using Scala for composable, type-safe queries. Hibernate has different features.

If you still think it is a good idea, threadLocalSession together with using db.withSession { ... } instead of db.withSession {  implicit s: Session => ... } may help you

http://slick.typesafe.com/doc/1.0.0/gettingstarted.html

Bandar Bandirsen

unread,
Mar 22, 2013, 1:12:18 PM3/22/13
to scala...@googlegroups.com
Following up your suggestion, everything is works fine

I'm a bit worry about that threadLocalSession, since its not a safe-way in multithread environment
but I think that the only way to "re-using" opened session while avoiding implicit session parameter

Thanks

Clint Gilbert

unread,
Mar 22, 2013, 2:07:55 PM3/22/13
to scala...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I'm not sure I understand the problem, but couldn't you add a Database
parameter to your Slick DAO class, and surround the bodies of its
methods with db.withSession{ ... } calls? As in

class SlickDao(db: Database) extends AbstractDao {
override def savePerson(id: String, name: String) {
db.withSession { implicit session =>
...
}
}
override def findPersion(n: Name): List[(String, String)] = {
db.withSession { implicit session =>
...
> --
>
> --- You received this message because you are subscribed to the
> Google Groups "Slick / ScalaQuery" group. To unsubscribe from this
> group and stop receiving emails from it, send an email to
> scalaquery+...@googlegroups.com. For more options, visit
> https://groups.google.com/groups/opt_out.
>
>

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with undefined - http://www.enigmail.net/

iEYEARECAAYFAlFMnfsACgkQ5IyIbnMUeTvjcwCdGs2sVvegiI9GAx3P0pM+y0Oj
9f0An1gPHAha9lxMedTKi8xrOCDnwnXD
=JKVt
-----END PGP SIGNATURE-----

Clint Gilbert

unread,
Mar 22, 2013, 2:09:38 PM3/22/13
to scala...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 03/22/2013 11:03 AM, Christopher Vogt wrote:
> Abstracting over Slick and Hibernate is probably not a good idea

I don't think this is /necessarily/ true. Given the OP's DAO trait,
there's no reason he couldn't create Hibernate and Slick
implementations. (But of course, I wouldn't recommend Hibernate in
general.)


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with undefined - http://www.enigmail.net/

iEYEARECAAYFAlFMnmIACgkQ5IyIbnMUeTvQZgCeNuN7sSLT0pSEeFr1lHY79JT0
SOoAoKOoduYfubVzWu8rLd/JUc1VBhb8
=W4PN
-----END PGP SIGNATURE-----

Bandar Bandirsen

unread,
Mar 22, 2013, 7:43:35 PM3/22/13
to scala...@googlegroups.com
Hi clint,

If I follow your example, how to call both methods in one transaction, for example

db.withTransaction {       
  slickDAO.savePerson() 
  slickDAO.findPerson()  
}

this gonna open session 3 times, and break the transaction

in real world, I think its common to call some DAO methods in one session or transaction in a part of our code, while in another part of our code we only we call one DAO method

Correct me if I'm wrong, actually Hibernate not did not survive from this problem too, they are also using threadlocal too to save session just like slick, so they are not safe in multi-thread environment.

I'm agre with you, I prefer slick over hibernate.


btw, this is my new approach as Christoper suggestion

case class Person(id: String, name: String)

trait PersonDAO {

 def savePerson(id: String, name: String): Unit
 def getPerson: (String, String)
}

object SlickPersonDAO extends PersonDAO {
  import import scala.slick.driver.PostgresDriver.simple._
  import Database.threadLocalSession               // implicit session for all DAO methods, to "re-using" avaiable session on current thread


  object PersonTable extends Table[(String, String)]("person") {
    def personId = column[String]("id", O.NotNull)
    def name = column[String]("name", O.NotNull)
    def baseProjection = personId ~ name
    def * = baseProjection
    val findByName = createFinderBy(_.name)
  }
 
  // no (implicit s: Session) or "implicit s: Session =>"  since we already import threadLocalSession
  override def savePerson(id: Person, name: String): Unit {
    PersonTable.insert(id, name)
  }
 
  override def getPerson: (String, String) =
    PersonTable.findByName(name).firstOption 
 
}

// somewhere in my application, now we are freely to call single method within a session
db.withSession {
  slickDAO.getPerson("name") 
}

// or call some DAO methods within a transaction
db.withTransaction {
  val personData = slickDAO.getPerson("a name")
  slickDAO.savePerson(personData._1, "newName") 
}

btw,, I keep open my eyes for another approach

Regards,
Bandirsen





.

Clint Gilbert

unread,
Mar 27, 2013, 2:29:57 PM3/27/13
to scala...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Aha, of course, you're right, Bandar. I'm a bit embarassed I didn't
think of this issue earlier. Using threadLocalSession is the best way
I can think of, too.
> --
>
> --- You received this message because you are subscribed to the
> Google Groups "Slick / ScalaQuery" group. To unsubscribe from this
> group and stop receiving emails from it, send an email to
> scalaquery+...@googlegroups.com. For more options, visit
> https://groups.google.com/groups/opt_out.
>
>

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with undefined - http://www.enigmail.net/

iEYEARECAAYFAlFTOqUACgkQ5IyIbnMUeTsVpQCfY69Ip7Iu40IBf5HIFVQACjlI
XkIAnR4WgbR+OnIwoUD1q3MIcEQKEgg6
=2rVG
-----END PGP SIGNATURE-----
Reply all
Reply to author
Forward
0 new messages