squerylrecord.CRUDify - no session is bound to current thread

452 views
Skip to first unread message

Olek Swirski

unread,
Dec 5, 2011, 9:41:30 AM12/5/11
to Lift
I'm trying to use net.liftweb.squerylrecord.CRUDify.
I use lift 2.4-M5, jetty 8 + H2 in-memory database.
For testing I set up a simple User entity. In User meta
object I changed the default location for CRUDify pages:
override lazy val Prefix = List("root","users").

list and create CRUDify pages are accessible under
localhost:8080/root/users/list &
localhost:8080/root/users/create as expected, however
delete, edit & view pages all return the following exception:

Exception occured while processing /root/users/view/1
Message: java.lang.RuntimeException: no session is bound to current
thread, a session must be created via Session.create
and bound to the thread via 'work' or 'bindToCurrentThread'

I understand, all calls to squeryl need to reside in a transaction
block. This is why I used the following code in my Boot.scala:
S.addAround(new LoanWrapper{override def apply[T](f: => T): T =
{inTransaction{f}}})
For some reason this works only with list and create pages.
Other pages throw exception.

Please, does anybody know why is it so or how to fix it?
I will gladly provide any further details needed.

Ján Raska

unread,
Dec 5, 2011, 11:11:00 AM12/5/11
to lif...@googlegroups.com
Hi Olek,

do you have your Squeryl Session initialized in Boot.scala?

It would be very helpful if you could setup a runnable example (https://www.assembla.com/wiki/show/liftweb/Posting_example_code,  preferably  using git, but I can handle maven too) and post it to GitHub. This sort of error can appear for several reasons, so it's hard for me to tell, without seeing all your code.

Thanks

Jan


Peter Petersson

unread,
Dec 5, 2011, 11:27:00 AM12/5/11
to lif...@googlegroups.com
This may be a workaround however I don't know if this is the right
approach but in addition to the loanwrapper function I have found the
need to surround some db calls with
net.liftweb.squerylrecord.RecordTypeMode.transaction to avoid the same
exception.
example:
def prepareAllCountryCodes(): List[CountryCodes] = transaction {
List(

CountryCodes.createRecord.a2("AF").a3("AFG").num(4).country("AFGHANISTAN"),

CountryCodes.createRecord.a2("AL").a3("ALB").num(8).country("ALBANIA"),
:

It would be great if someone could explain why this is needed (well I
guess the call is done outside of a session ;) )

best regards
Peter Petersson

On 2011-12-05 15:41, Olek Swirski wrote:
> I'm trying to use net.liftweb.squerylrecord.CRUDify.
> I use lift 2.4-M5, jetty 8 + H2 in-memory database.
> For testing I set up a simple User entity. In User meta
> object I changed the default location for CRUDify pages:
> override lazy val Prefix = List("root","users").
>
> list and create CRUDify pages are accessible under
> localhost:8080/root/users/list&
> localhost:8080/root/users/create as expected, however

> delete, edit& view pages all return the following exception:

Ján Raska

unread,
Dec 5, 2011, 11:41:04 AM12/5/11
to lif...@googlegroups.com

On Dec 5, 2011, at 17:27 , Peter Petersson wrote:

> This may be a workaround however I don't know if this is the right approach but in addition to the loanwrapper function I have found the need to surround some db calls with net.liftweb.squerylrecord.RecordTypeMode.transaction to avoid the same exception.
> example:
> def prepareAllCountryCodes(): List[CountryCodes] = transaction {
> List(
> CountryCodes.createRecord.a2("AF").a3("AFG").num(4).country("AFGHANISTAN"),
> CountryCodes.createRecord.a2("AL").a3("ALB").num(8).country("ALBANIA"),
> :
>
> It would be great if someone could explain why this is needed (well I guess the call is done outside of a session ;) )

Basically, all that the loanWrapper does is that it wraps the entire request within a transaction. So as far as you are within the scope of a request, you should be fine. However, if you are outside of request scope, you need to wrap all database calls with a transaction{} or inTransaction{} block. A good example is a Boot.scala, if you do something with a database in Boot (eg. I do some caching there in some applications) it needs to go inside transaction{} block, because there is no request, thus loanWrapper doesn't take place.

Does that answer your question?


>
> best regards
> Peter Petersson
>
> On 2011-12-05 15:41, Olek Swirski wrote:
>> I'm trying to use net.liftweb.squerylrecord.CRUDify.
>> I use lift 2.4-M5, jetty 8 + H2 in-memory database.
>> For testing I set up a simple User entity. In User meta
>> object I changed the default location for CRUDify pages:
>> override lazy val Prefix = List("root","users").
>>
>> list and create CRUDify pages are accessible under
>> localhost:8080/root/users/list&
>> localhost:8080/root/users/create as expected, however
>> delete, edit& view pages all return the following exception:
>>
>> Exception occured while processing /root/users/view/1
>> Message: java.lang.RuntimeException: no session is bound to current
>> thread, a session must be created via Session.create
>> and bound to the thread via 'work' or 'bindToCurrentThread'
>>
>> I understand, all calls to squeryl need to reside in a transaction
>> block. This is why I used the following code in my Boot.scala:
>> S.addAround(new LoanWrapper{override def apply[T](f: => T): T =
>> {inTransaction{f}}})
>> For some reason this works only with list and create pages.
>> Other pages throw exception.
>>
>> Please, does anybody know why is it so or how to fix it?
>> I will gladly provide any further details needed.
>>
>

Peter Petersson

unread,
Dec 5, 2011, 11:48:33 AM12/5/11
to lif...@googlegroups.com, Ján Raska
On 2011-12-05 17:41, J�n Raska wrote:
> On Dec 5, 2011, at 17:27 , Peter Petersson wrote:
>
>> This may be a workaround however I don't know if this is the right approach but in addition to the loanwrapper function I have found the need to surround some db calls with net.liftweb.squerylrecord.RecordTypeMode.transaction to avoid the same exception.
>> example:
>> def prepareAllCountryCodes(): List[CountryCodes] = transaction {
>> List(
>> CountryCodes.createRecord.a2("AF").a3("AFG").num(4).country("AFGHANISTAN"),
>> CountryCodes.createRecord.a2("AL").a3("ALB").num(8).country("ALBANIA"),
>> :
>>
>> It would be great if someone could explain why this is needed (well I guess the call is done outside of a session ;) )
> Basically, all that the loanWrapper does is that it wraps the entire request within a transaction. So as far as you are within the scope of a request, you should be fine. However, if you are outside of request scope, you need to wrap all database calls with a transaction{} or inTransaction{} block. A good example is a Boot.scala, if you do something with a database in Boot (eg. I do some caching there in some applications) it needs to go inside transaction{} block, because there is no request, thus loanWrapper doesn't take place.
>
> Does that answer your question?
yes that clearly explains why I needed it wile doing db init stuff.
thanks

Olek Swirski

unread,
Dec 5, 2011, 11:59:14 PM12/5/11
to lif...@googlegroups.com
ok, I will put example code on github. sorry for the duplicated topic - I submitted the other one much earlier and I thought that maybe it got moderated as it was too long or something, so I shortened it and sent again.

On 5 December 2011 17:48, Peter Petersson <peterss...@gmail.com> wrote:

Olek Swirski

unread,
Dec 6, 2011, 1:05:03 PM12/6/11
to lif...@googlegroups.com
ok, I have put a stripped down version of my problematic lift-app on github
git://github.com/oolekk/dist_test.git
there is only index.html in webapp dir and from there list and create pages generated by CRUDify are accesible. when I go to the list page I can see 2 rows initialized within Boot.scala, there are also links to edit, delete, view pages, but these throw Exception. So the question is, what to do for it to work as expected? It's quite possible I made some basic mistake so please forgive if this is the case :) Exception type makes me think, that for some reason transaction-wrapping doesn't work for delete,edit & view pages. But maybe the problem is with db connection - however some initial data is loaded without problem into db in Boot.scala. in-memory DB can be monitored under http://localhost:8080/console/ after starting this app in sbt (container:start).  Another possible reason is maybe due to the fact that I try to use connection pooler - BoneCP, but I guess it's needed to get reasonable performance. Any help will be greately appreciated :-)

Olek Swirski

unread,
Dec 7, 2011, 2:10:02 AM12/7/11
to Lift
I checked if the same thing happens when I use MySQL instead of H2 db,
and noticed that with MySQL even the list CRUDify page is gone. I now
think, that the source of my problem is probably in BoneCP connection
pool configuration and not in CRUDify or squeryl-record.

On Dec 6, 7:05 pm, Olek Swirski <olekswir...@gmail.com> wrote:
> ok, I have put a stripped down version of my problematic lift-app on github
> git://github.com/oolekk/dist_test.git
> there is only index.html in webapp dir and from there list and create pages
> generated by CRUDify are accesible. when I go to the list page I can see 2
> rows initialized within Boot.scala, there are also links to edit, delete,
> view pages, but these throw Exception. So the question is, what to do for
> it to work as expected? It's quite possible I made some basic mistake so
> please forgive if this is the case :) Exception type makes me think, that
> for some reason transaction-wrapping doesn't work for delete,edit & view
> pages. But maybe the problem is with db connection - however some initial
> data is loaded without problem into db in Boot.scala. in-memory DB can be

> monitored underhttp://localhost:8080/console/after starting this app in


> sbt (container:start).  Another possible reason is maybe due to the fact
> that I try to use connection pooler - BoneCP, but I guess it's needed to
> get reasonable performance. Any help will be greately appreciated :-)
>

> On 6 December 2011 05:59, Olek Swirski <olekswir...@gmail.com> wrote:
>
>
>
>
>
>
>
> > ok, I will put example code on github. sorry for the duplicated topic - I
> > submitted the other one much earlier and I thought that maybe it got
> > moderated as it was too long or something, so I shortened it and sent again.
>

> > On 5 December 2011 17:48, Peter Petersson <petersson.pe...@gmail.com>wrote:
>
> >> On 2011-12-05 17:41, Ján Raska wrote:
>
> >>> On Dec 5, 2011, at 17:27 , Peter Petersson wrote:
>
> >>>  This may be a workaround however I don't know if this is the right
> >>>> approach but in addition to the loanwrapper function I have found the need

> >>>> to surround some db calls with net.liftweb.squerylrecord.**RecordTypeMode.transaction


> >>>> to avoid the same exception.
> >>>> example:
> >>>>  def prepareAllCountryCodes(): List[CountryCodes] = transaction {
> >>>>    List(

> >>>>      CountryCodes.createRecord.a2("**AF").a3("AFG").num(4).country(**
> >>>> "AFGHANISTAN"),
> >>>>      CountryCodes.createRecord.a2("**AL").a3("ALB").num(8).country(**


> >>>> "ALBANIA"),
> >>>>      :
>
> >>>> It would be great if someone could explain why this is needed (well I
> >>>> guess the call is done outside of a session ;) )
>
> >>> Basically, all that the loanWrapper does is that it wraps the entire
> >>> request within a transaction. So as far as you are within the scope of a
> >>> request, you should be fine. However, if you are outside of request scope,
> >>> you need to wrap all database calls with a transaction{} or inTransaction{}
> >>> block. A good example is a Boot.scala, if you do something with a database
> >>> in Boot (eg. I do some caching there in some applications) it needs to go
> >>> inside transaction{} block, because there is no request, thus loanWrapper
> >>> doesn't take place.
>
> >>> Does that answer your question?
>
> >> yes that clearly explains why I needed it wile doing db init stuff.
> >> thanks
>
> >>>  best regards
> >>>>   Peter Petersson
>
> >>>> On 2011-12-05 15:41, Olek Swirski wrote:
>

> >>>>> I'm trying to use net.liftweb.squerylrecord.**CRUDify.


> >>>>> I use lift 2.4-M5, jetty 8 + H2 in-memory database.
> >>>>> For testing I set up a simple User entity. In User meta
> >>>>> object I changed the default location for CRUDify pages:
> >>>>> override lazy val Prefix = List("root","users").
>
> >>>>> list and create CRUDify pages are accessible under

> >>>>> localhost:8080/root/users/**list&
> >>>>> localhost:8080/root/users/**create as expected, however


> >>>>> delete, edit&   view pages all return the following exception:
>
> >>>>> Exception occured while processing /root/users/view/1
> >>>>> Message: java.lang.RuntimeException: no session is bound to current
> >>>>> thread, a session must be created via Session.create
> >>>>> and bound to the thread via 'work' or 'bindToCurrentThread'
>
> >>>>> I understand, all calls to squeryl need to reside in a transaction
> >>>>> block. This is why I used the following code in my Boot.scala:
> >>>>> S.addAround(new LoanWrapper{override def apply[T](f: =>   T): T =
> >>>>> {inTransaction{f}}})
> >>>>> For some reason this works only with list and create pages.
> >>>>> Other pages throw exception.
>
> >>>>> Please, does anybody know why is it so or how to fix it?
> >>>>> I will gladly provide any further details needed.
>
> >>>>>  --
> >>>> Lift, the simply functional web framework:http://liftweb.net
> >>>> Code:http://github.com/lift

> >>>> Discussion:http://groups.google.com/**group/liftweb<http://groups.google.com/group/liftweb>
> >>>> Stuck? Help us help you:https://www.assembla.com/wiki/**
> >>>> show/liftweb/Posting_example_**code<https://www.assembla.com/wiki/show/liftweb/Posting_example_code>


>
> >> --
> >> Lift, the simply functional web framework:http://liftweb.net
> >> Code:http://github.com/lift

> >> Discussion:http://groups.google.com/**group/liftweb<http://groups.google.com/group/liftweb>
> >> Stuck? Help us help you:https://www.assembla.com/wiki/**
> >> show/liftweb/Posting_example_**code<https://www.assembla.com/wiki/show/liftweb/Posting_example_code>

Peter Petersson

unread,
Dec 7, 2011, 2:36:30 AM12/7/11
to lif...@googlegroups.com

I have already tried that and disabled your pool and also the servlet
filter wile at it but still same error.
best regards
Peter Petersson

On 2011-12-07 08:10, Olek Swirski wrote:
> I checked if the same thing happens when I use MySQL instead of H2 db,
> and noticed that with MySQL even the list CRUDify page is gone. I now
> think, that the source of my problem is probably in BoneCP connection
> pool configuration and not in CRUDify or squeryl-record.
>
> On Dec 6, 7:05 pm, Olek Swirski<olekswir...@gmail.com> wrote:
>> ok, I have put a stripped down version of my problematic lift-app on github
>> git://github.com/oolekk/dist_test.git
>> there is only index.html in webapp dir and from there list and create pages
>> generated by CRUDify are accesible. when I go to the list page I can see 2
>> rows initialized within Boot.scala, there are also links to edit, delete,
>> view pages, but these throw Exception. So the question is, what to do for
>> it to work as expected? It's quite possible I made some basic mistake so
>> please forgive if this is the case :) Exception type makes me think, that

>> for some reason transaction-wrapping doesn't work for delete,edit& view


>> pages. But maybe the problem is with db connection - however some initial
>> data is loaded without problem into db in Boot.scala. in-memory DB can be
>> monitored underhttp://localhost:8080/console/after starting this app in
>> sbt (container:start). Another possible reason is maybe due to the fact
>> that I try to use connection pooler - BoneCP, but I guess it's needed to
>> get reasonable performance. Any help will be greately appreciated :-)
>>
>> On 6 December 2011 05:59, Olek Swirski<olekswir...@gmail.com> wrote:
>>
>>
>>
>>
>>
>>
>>
>>> ok, I will put example code on github. sorry for the duplicated topic - I
>>> submitted the other one much earlier and I thought that maybe it got
>>> moderated as it was too long or something, so I shortened it and sent again.
>>> On 5 December 2011 17:48, Peter Petersson<petersson.pe...@gmail.com>wrote:

Olek Swirski

unread,
Dec 7, 2011, 2:52:40 AM12/7/11
to lif...@googlegroups.com
so this would indicate, that BoneCP is not the culprit. thank you for your feedback I will continue my quest and with help from you folks, there is hope :)


Olek Swirski

unread,
Dec 7, 2011, 3:42:30 AM12/7/11
to lif...@googlegroups.com
??? Can anyone confirm successfully combining these 3 things ???:
1) squeryl-record based entity with CRUDify trait
2) request-transaction wrapping with something alike the line below

S.addAround(new LoanWrapper{override def apply[T](f: => T): T = {inTransaction{f}}})
3) properly working CRUDify pages (especially delete, view, edit)

If yes, then this would prove, that the functionality is there, and starting from a working example I should be able to have my app working and possibly find where the problem was.

It is strange that for example the 'add' CRUDify-generated page works well and adds new entities (at least with H2 db - but not so with MySQL where I saw all the CRUDify pages fail). So it is supprising for me, that while some pages work the others dont't work and throw 'no session is bound to current thread'.

Peter Petersson

unread,
Dec 7, 2011, 8:12:48 AM12/7/11
to lif...@googlegroups.com
... also i added some debug info and it looks to me that your
loanwrapper is invoked as it should

12:16:29.865 [qtp1560165012-41738 - /user/view/1] INFO bootstrap.liftweb.Boot - LOANWRAPPER INTRANSACTION Full(Req(List(), Map(), ParsePath(List(user, view, 1),,true,false), , GetRequest, Empty))
12:16:29.943 [qtp1560165012-41738 - /user/view/1] ERROR net.liftweb.http.LiftRules - Exception being returned to browser when processing /user/view/1: Message: java.lang.RuntimeException: no session is bound to current thread, a session must be created via Session.create


and bound to the thread via 'work' or 'bindToCurrentThread'

but yes there are some rewrites going on.

I have stripped down your example as much as I can, removing the pool,
session factory, servlet filtering and messing around with the crudify
stuff, but I am afraid I am a novice when it comes to the CRUDify stuff
so your question stands why dose clicking on the delete, view, edit
links on the "crudified"-page result in the "no session is bound to
current thread" error when create is working great.

The only thing that comes to my mind when it come to the crudify stuff
is that crudify create of a new user do no involve lookup by a Id field
wiles all of delete, view and edit needs it, so for instance how dose
the crudify stuff translate the path "/user/view/1" into a view of user
data for id=1 ?

It has been a fun ride but I am afraid to no or little avail for you but
the in-memory-db/console stuff is definitely cool so thanks for the
example.

Hopefully someone else will jump in and take a stab at this.

best regards
Peter Petersson

Olek Swirski

unread,
Dec 7, 2011, 10:44:02 AM12/7/11
to lif...@googlegroups.com
I'm happy that you find this useful. Some pre-configured lift app with squeryl-record could be a nice starting point for many people. I myself would be very happy to find a working prototype of squeryl-record + transaction wrapping + connection-pooling + initial db setup with H2 and www console acces (with option to choose other db) + template squeryl entity + functional CRUDify. Now if I get this last missing element, the quest for the Holly Grail wil succeed and I will be happy to share. At this point however, I have no idea what am I missing with CRUDify ?? Anybody there has some idea how to make CRUDify generated pages behave properly with squeryl-record based entity :) ?? Seems to me like a pretty typical scenario (?), so maybe someone already got it right?


David Whittaker

unread,
Dec 7, 2011, 10:48:03 AM12/7/11
to lif...@googlegroups.com
Olek,

I'm looking at it now.  I'll get back to you shortly.

Olek Swirski

unread,
Dec 7, 2011, 10:50:16 AM12/7/11
to lif...@googlegroups.com
superb! thank you.

Peter Petersson

unread,
Dec 7, 2011, 11:13:20 AM12/7/11
to lif...@googlegroups.com
Yes thanks Olek I just added the console stuff to my basic squeryl record user setup example (it has what you ask for below except for the crudify stuff)
https://github.com/karma4u101/Basic-SquerylRecord-User-Setup

Looking forward to see what David finds

best regards
   Peter Petersson

David Whittaker

unread,
Dec 7, 2011, 2:41:55 PM12/7/11
to lif...@googlegroups.com
Olek,

It seems that the scope of a LoanWrapper has somehow changed since I put this together.  Originally I know it had been working, but now the transaction doesn't seem to exist before the rewrite checks if the ID is valid, and everything blows up.  The real fix will have to be updating the CRUDify trait and wrapping all database access with inTransaction{} blocks, but until that is done I've made some updates to your test to show you how to work around it.  Take a look here:


Most importantly:


I'll see if I can get a real fix into Lift 2.4, but until then this should give you what you need.

-Dave

Olek Swirski

unread,
Dec 8, 2011, 12:25:05 AM12/8/11
to lif...@googlegroups.com
David, with your fix now it works perfectly. I imagined that finding some method in CRUDify, to wrap it inside transaction explicitly, was the way to go, but because of my limited understanding I would have no idea which one to begin with. Also I read these 3 modified files you made. I noticed how you improved my clumsy attempt on using connection pool from BoneCP. Looks good now. Also my sbt config - jetty related lines. It's a great lesson for me to see a pro at work. I understand, the fix with
override def findForParam(in: String): Box[TheCrudType] =
  inTransaction {
    table.lookup(idFromString(in))
   }
in entity object definition won't be neccessary anymore if a general solution makes it into 2.4 (?). Anyway, I was stuck and now I'm back on track :) !! Big Thanks !!

Also I'm happy that Peter's Basic-SquerylRecord-User-Setup example has profited from this discussion. It's so cool to watch the code-kitchen at work.

Olek Swirski

unread,
Dec 8, 2011, 2:23:50 AM12/8/11
to lif...@googlegroups.com
Peter, I just read the files from your Basic-SquerylRecord-User-Setup example app and it has all I need in a much more elegant & flexible style than what I managed to come up with. With David's fix it is very easy to make CRUDify pages functional, so I imagine, you may also include CRUDify, or put it as optional feature. You may want to check David's PoolProvider stuff too - looks much better to me than the attempt I made. So, to put it short - I will use your Basic-SquerylRecord-User-Setup example code as basis for my app. !! Thank you !!

Peter Petersson

unread,
Dec 8, 2011, 4:29:09 AM12/8/11
to lif...@googlegroups.com, Olek Swirski
Yes I just pushed some updates regarding the pool init It's slightly different from Davids though as the example supports configurations for both H2 in-memory db, MySql and Postgres (I have made the pool stuff a "one liner hookup" so its very easy to enable disable).
I have updated the code I cloned from you  yesterday with Davids fixes so I now have a working copy of your crudify stuff and yes having followed the development of this my thoughts is to eventualy include a curidfied admin section in my example code. I am glad you find my example useful as I did yours :).

Thank you Olek and David

best regards
   Peter Petersson  
Reply all
Reply to author
Forward
0 new messages