Problem using lifecycle callbacks

146 views
Skip to first unread message

Olek Swirski

unread,
Apr 28, 2012, 11:34:01 AM4/28/12
to Squeryl
hi, I noticed that when it comes to lifecycle callbacks I can only
reliably use beforeInsert and afterInsert. beforeUpdate is called only
with initial insert, and no update related callbacks are called when
updating existing row. also delete related callbacks won't fire.

I'm not very experienced squeryl user, so it can be that I'm missing
some important point, may be that my setup is flawed (I mean,
build.sbt ??), or maybe lifecycle functionality is just not yet fully
supported as I understand it's a new feature. please let me know.

here I prepared a simple LIFT app that demonstrates the problem:
g...@github.com:oolekk/sqrlrcrd.com.git

this is what I get, when running this app - update & delete callbacks
don't fire as expected when using either h2 or mysql (tried to check
postgres too, but I had some trouble connecting to my local postgres
db, perhaps wrong URL or access permissions)

17:03:57.533 [pool-6-thread-1] DEBUG c.s.m.MySchemaHelper
$MyH2DBSettings - MyH2DBSettings: seting adapter=H2Adapter
driver=org.h2.Driver
url=jdbc:h2:mem:sqrlrcrd_com;DB_CLOSE_DELAY=-1;LOCK_TIMEOUT=3000
user=test pw=
17:03:57.535 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchemaHelper
- initSquerylRecord with DBSettings: driver=org.h2.Driver
url=jdbc:h2:mem:sqrlrcrd_com;DB_CLOSE_DELAY=-1;LOCK_TIMEOUT=3000
user=test pw=
17:03:57.985 [pool-6-thread-1] WARN com.jolbox.bonecp.BoneCPConfig -
Max Connections < 1. Setting to 20
17:03:59.353 [pool-6-thread-1] INFO c.s.m.MySchemaHelper$PoolProvider
- BoneCP connection pool is now initialized.
-- table declarations :
create table msr (
name varchar(100) not null,
id bigint not null primary key auto_increment
);
17:04:00.327 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData -
about to insert foo & bar
17:04:00.426 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
beforeInsert
17:04:00.428 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
beforeUpdate
17:04:00.428 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
beforeInsert
17:04:00.428 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
beforeUpdate
17:04:00.463 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
beforeInsert
17:04:00.463 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
beforeUpdate
17:04:00.467 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
beforeInsert
17:04:00.471 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
beforeUpdate
17:04:00.482 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
afterInsert
17:04:00.482 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
afterInsert
17:04:00.497 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData - foo
& bar inserted
17:04:00.499 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData -
about to insert baz
17:04:00.506 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
beforeInsert
17:04:00.507 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
beforeUpdate
17:04:00.567 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema -
afterInsert
17:04:00.580 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData - baz
inserted
17:04:00.582 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData -
about to update baz
17:04:00.675 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData - baz
updated
17:04:00.677 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData -
about to delete foo
17:04:00.744 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData - foo
deleted
17:04:00.745 [pool-6-thread-1] INFO bootstrap.liftweb.Boot -
RunMode is DEVELOPMENT @ sqrlrcrd.com

Olek Swirski

unread,
Apr 28, 2012, 11:43:37 AM4/28/12
to Squeryl
I didn't include https link to git repo, so here it is

https://github.com/oolekk/sqrlrcrd.com
g...@github.com:oolekk/sqrlrcrd.com.git

Maxime Lévesque

unread,
Apr 28, 2012, 11:50:48 AM4/28/12
to squ...@googlegroups.com

Could it be that at line 22 : 

 https://github.com/oolekk/sqrlrcrd.com/blob/master/src/main/scala/com/sqrlrcrd/model/MySchema.scala#L22

The log message is incorrect ?

You have  logger.debug("afterUpdate")

it should be logger.debug("afterDelete")

?

2012/4/28 Olek Swirski <oleks...@gmail.com>



--
Seuls les poissons morts nagent avec le courant

Olek Swirski

unread,
Apr 28, 2012, 12:07:24 PM4/28/12
to squ...@googlegroups.com
ok, I correcteth this @ github

I did this:

    /* lifecycle callbacks */
    override def callbacks = Seq(
           
        beforeInsert(msrs) call (MySqrlRcrd => logger.debug("beforeInsert")),
        beforeUpdate(msrs) call (MySqrlRcrd => logger.debug("beforeUpdate")),
        beforeDelete(msrs) call (MySqrlRcrd => logger.debug("beforeDelete")),
        afterInsert(msrs) call (MySqrlRcrd => logger.debug("afterInsert")),
        afterUpdate(msrs) call (MySqrlRcrd => logger.debug("afterUpdate")),
        afterDelete(msrs) call (MySqrlRcrd => logger.debug("afterDelete"))

    )

and DemoData dos insert, update, and delete some rows:

    def createDemoData = {
        /* *
     * we can use a List as insert argument
     * to batch insert all  the items
     * */
    
    
    logger.debug("about to insert foo & bar");
        transaction{MySchema.msrs.insert(prepareMySqrlRcrds())}
        logger.debug("foo & bar inserted");
       
        logger.debug("about to insert baz");
        val baz = MySqrlRcrd.createRecord name("baz")
        transaction{MySqrlRcrd.table.insert(baz)}
        logger.debug("baz inserted");
       
        logger.debug("about to update baz");
        transaction{
            update(MySqrlRcrd.table)(msr => where(msr.name === "baz") set(msr.name := "Baz"))}
        logger.debug("baz updated");
       
        logger.debug("about to delete foo");
        transaction{
            MySqrlRcrd.table.deleteWhere(msr => msr.name === "foo")}
        logger.debug("foo deleted");

    }

so I think I should be seeing some lines like these:

17:56:57.139 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema - beforeUpdate
or:
17:56:57.139 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema - beforeDelete
or:
17:56:57.139 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema - afterDelete
or:
17:56:57.139 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.MySchema - afterUpdate

in between:

17:56:57.203 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData - about to update baz
17:56:57.314 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData - baz updated
17:56:57.316 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData - about to delete foo
17:56:57.406 [pool-6-thread-1] DEBUG com.sqrlrcrd.model.DemoData - foo deleted

where did I go wrong? :)

Maxime Lévesque

unread,
Apr 28, 2012, 12:22:52 PM4/28/12
to squ...@googlegroups.com

Ok, what happens here is that  lifecycle events are *not* supported for partial updates :

    update(MySqrlRcrd.table)(msr => where(msr.name === "baz") set(msr.name := "Baz"))}

This should probably be documented  *cough* ...  the reason is that such an update 
never fetches the object from the DB, it would be very inefficient if it did.
The main reason to use partial updates (and deleteWhere) is for it's efficiency, firing 
events on them would require to load all objects beforehand, making them less efficient
than object based updates.
The same goes for yourTable.deleteWhere(...)


2012/4/28 Olek Swirski <oleks...@gmail.com>

Olek Swirski

unread,
Apr 28, 2012, 1:17:04 PM4/28/12
to squ...@googlegroups.com
ok, so I understand, that only when I update whole record and not
some particular field within it, update related callbacks will be fired?

I mean from http://squeryl.org/inserts-updates-delete.html
I understand I should use something like

        val foo = MySqrlRcrd.table.lookup(1L).get
        foo.name = "Foo"
        transaction{MySqrlRcrd.table.update(foo)}

to make a full update. this however doesn't seem to work with lift's
Record because name is of type StringField, and it is a val, so
I can't reassign it to "Foo" which is String


transaction{
            update(MySqrlRcrd.table)(msr => where(msr.name === "baz") set(msr.name := "Baz"))
}

does work, but it's only partial update. So I don't
know how to make a full update when using lift Record.
i tried using where(msr.id === 1L) but it makes no difference

similarly if deleteWhere doesn't trigger callback  how should I perform
delete to have beforeDelete or afterDelete work?

I guess my problem has something to do with how Record works with
squeryl, and my question should be how to do full update when using
squeryl with lift's Record and how to trigger delete calbacks when
using squeryl with lift's Record? What should I change in my app to make
them fire?

Olek Swirski

unread,
Apr 28, 2012, 2:26:36 PM4/28/12
to squ...@googlegroups.com
I understand that partial update is much more efficient, and
also deleteWhere, when it doesn't fetch object from db is
way faster, but still I would like to know, how do I trigger
these delete & update callbacks (with lift's Record).

David Whittaker

unread,
Apr 28, 2012, 2:39:23 PM4/28/12
to squ...@googlegroups.com
On Sat, Apr 28, 2012 at 1:17 PM, Olek Swirski <oleks...@gmail.com> wrote:
ok, so I understand, that only when I update whole record and not
some particular field within it, update related callbacks will be fired?

I mean from http://squeryl.org/inserts-updates-delete.html
I understand I should use something like

        val foo = MySqrlRcrd.table.lookup(1L).get
        foo.name = "Foo"
        transaction{MySqrlRcrd.table.update(foo)}

to make a full update. this however doesn't seem to work with lift's
Record because name is of type StringField, and it is a val, so
I can't reassign it to "Foo" which is String


transaction{
            update(MySqrlRcrd.table)(msr => where(msr.name === "baz") set(msr.name := "Baz"))
}


Hi Olek,

The way you would do this with record would be:

transaction {
  MySqrlRcrd.table.lookup(1) map { rec =>
    rec.name("Baz")
    MySqrlRcrd.table.update(rec)
  }
}

While record fields are generally stored as vars, the value that the represent can be set with their apply() methods.

Olek Swirski

unread,
Apr 28, 2012, 3:25:15 PM4/28/12
to squ...@googlegroups.com
thx David,

using this syntax afterUpdate is called as expected :)
now I tried to make delete callback happen using this:

        logger.debug("about to do full delete of foo")
        transaction {
            MySqrlRcrd.table.lookup(1L) map { rec =>
                MySqrlRcrd.table.delete(rec)
            }
        }
        logger.debug("foo deleted")

but I get

[info] Compiling 1 Scala source to /home/olo/www/sqrlrcrd.com/target/scala-2.9.1/classes...
[error] /home/olo/www/sqrlrcrd.com/src/main/scala/com/sqrlrcrd/model/DemoData.scala:42: Cannot prove that com.sqrlrcrd.model.MySqrlRcrd <:< org.squeryl.KeyedEntity[com.sqrlrcrd.model.MySqrlRcrd].
[error]                 MySqrlRcrd.table.delete(rec)
[error]                                        ^
[error] one error found

and also I wonder, how does one trigger beforeUpdate. I noticed
it does fire when initial insert takes place. Is it possible to make it
fire also during some subsequent updates?

It's nothing urgent, I'm just curious to know how to make all these
triggers fire when used with Record.

Maxime Lévesque

unread,
Apr 28, 2012, 4:17:03 PM4/28/12
to squ...@googlegroups.com

You are getting the cannot prove... compile error because there is no
delete signature on table that takes a record type, only one that takes a
key with the id type.

however, the delete by key should fire the event : 



2012/4/28 Olek Swirski <oleks...@gmail.com>

Olek Swirski

unread,
Apr 28, 2012, 4:29:52 PM4/28/12
to squ...@googlegroups.com
ok thx, indeed this works :)

so last thing I still don't know  is how to trigger beforeUpdate?
(it does fire with initial insert, but not anymore later) even when
I use

    transaction {
        MySqrlRcrd.table.lookup(1L) map { rec =>
                rec.name("Foo")
                MySqrlRcrd.table.update(rec)
            }
   }



here are my delete callbacks working nicely when using delete by key

        logger.debug("about to do delete by key of foo - trigger callbacks")
        transaction {
            MySqrlRcrd.table.delete(1L)
        }
        logger.debug("foo deleted")
       

        logger.debug("about to delete bar - regular deleteWhere, no callbacks")
        transaction{
            MySqrlRcrd.table.deleteWhere(msr => msr.id === 2)}
        logger.debug("bar deleted")

22:22:03.271 [pool-9-thread-1] DEBUG com.sqrlrcrd.model.DemoData - about to do delete by key of foo - trigger callbacks
22:22:03.305 [pool-9-thread-1] DEBUG com.sqrlrcrd.model.MySchema - beforeDelete
22:22:03.315 [pool-9-thread-1] DEBUG com.sqrlrcrd.model.MySchema - afterDelete
22:22:03.321 [pool-9-thread-1] DEBUG com.sqrlrcrd.model.DemoData - foo deleted
22:22:03.322 [pool-9-thread-1] DEBUG com.sqrlrcrd.model.DemoData - about to delete bar - regular deleteWhere, no callbacks
22:22:03.381 [pool-9-thread-1] DEBUG com.sqrlrcrd.model.DemoData - bar deleted
Reply all
Reply to author
Forward
0 new messages