SQLite中如何用触发器执行取消和重做逻辑(1)
 作者:tamsyn 
 
这页主要描述一个使用SQLite作为主要数据结构的应用程序如何使用触发器去执行取消和重做逻辑。

我的想法是创建一个特殊的表格(例如名为撤销记录),表格保存数据库撤销和重做变化所需的信息。因为数据库中的每个表格都需要参与撤销和重做,每个DELETE,INSERT,和UPDATE都生成了触发器,DELETE,INSERT,和UPDATE可以在撤销日志表格中生成登记项,这个登记项将撤销操作。撤销表格中的登记项由一般的SQL语句组成,为了完成撤销,SQL语句可以被重新运行。

例如,如果你想在类似下面表格中执行撤销或重:

CREATE TABLE ex1(a,b,c);
Then triggers would be created as follows: 
  CREATE TEMP TRIGGER _ex1_it AFTER INSERT ON ex1 BEGIN
    INSERT INTO undolog VALUES(NULL,'DELETE FROM ex1 WHERE rowid='||new.rowid);
  END;
  CREATE TEMP TRIGGER _ex1_ut AFTER UPDATE ON ex1 BEGIN
    INSERT INTO undolog VALUES(NULL,'UPDATE ex1
       SET a='||quote(old.a)||',b='||quote(old.b)||',c='||quote(old.c)||'
     WHERE rowid='||old.rowid);
  END;
  CREATE TEMP TRIGGER _ex1_dt BEFORE DELETE ON ex1 BEGIN
    INSERT INTO undolog VALUES(NULL,'INSERT INTO ex1(rowid,a,b,c)
      VALUES('||old.rowid||','||quote(old.a)||','||quote(old.b)||
             ','||quote(old.c)||')');
  END;

在ex1表格中执行每个INSERT后, the _ex1_it 触发器生成DELETE语句的文本,它将撤销INSERT操作。 The _ex1_ut触发器生成UPDATE语句,这语句将取消一个UPDATE所产生的作用。_ex1_dt触发器生成一个语句,这语句将取消一个DELETE所具有的作用。

要注意quote()函数在这些触发器中的使用。quote()函数在SQLite中是标准的。它把它的参数转换成一种适合被包含在SQL语句中的形式。数字值不改变。单个的quotes被加在字符串之前或之后,任何内在的单个quotes都被逃逸。quote()函数被加入SQLite是为了执行撤销和重做操作。

当然,你也可以像上面一样用手生成触发器。但这个技术最突出的特点就是这些触发器可以自动生成。

例子中编码的语言是TCL。使用其它语言也是可以的,但是有可能要做更多工作。记住,这里的编码是demonstration技术,不是一个方便的模式,不能自动的为你做每件事。 下面所示的demonstration编码是源于程序执行过程中所使用的真实的代码。但你在使用它的时候,为了满足你的需要,你需要做些改变。

为了激活撤销和重做的逻辑,激活要参加撤销和重做的所有种类的(表格)undo::activate指令作为参数。用undo::deactivate, undo::freeze, and undo::unfreeze来控制undo/redo机制的状态。

The undo::activate指令在数据库中生成临时的触发器,它记录表格中所有被命名为参数的变化。

在一系列的改变定义了一个单独的undo/redo步骤后,激活undo::barrier指令来定义那步的局限性。在一个交互式的程序中,在做任何改动后,你可以调用undo::event,undo::barrier将被自动调用作为一个等待的回调。

当使用者按下Undo按钮,激活undo::undo。当使用者按下Redo按钮,激活undo::redo。

在调用undo::undo or undo::redo,undo/redo模块将自动在所有顶级有名字的空间激活程序status_refresh和reload_all。 这些程序应该被定义用来重建画面,或者更新基于undone/redon在数据库中变化的程序的状态。