タケユー・ウェブ日報

Ruby on Rails や Flutter といったWeb・モバイルアプリ技術を武器にお客様のビジネス立ち上げを支援する、タケユー・ウェブ株式会社の技術ブログです。

MT::Object::remove() でトランザクションが効かない件について

バグか仕様かわかりませんが嵌まったのでメモ。

こんなかんじでトランザクション使えますが、remove()の場合、begin_workで立てたはずのトランザクションを使うぞ!的なフラグを無視しやがるようです。

MT::Object でのトランザクション(Rollback / Commit) - フリーエンジニアライフ

my $entry = MT->model( 'entry' )->load();

$entry->begin_work;

$entry->remove();          # DELETE ...

$entry->rollback();        # だが何度でもよみがえ…らない!

先の記事で触れたとおり、Data::ObjectDriver::BaseObjectremove()などを使っている限り、これでDELETE文の前に$driver->begin_workトランザクションが開始されるはずなのです。

lib/MT/Object.pm を覗いてみると、remove()についてはオーバーライドで親クラスをすっ飛ばしてました。 これでは$driver->begin_work呼ばれません。

lib/MT/Object.pm

sub remove {
    my $obj = shift;
    my (@args) = @_;
    if ( !ref $obj ) {
        for my $which (qw( meta summary )) {
            my $meth = "remove_$which";
            my $has  = "has_$which";
            $obj->$meth(@args) if $obj->$has;
        }
        $obj->remove_scores(@args) if $obj->isa('MT::Scorable');
        MT->run_callbacks( $obj . '::pre_remove_multi', @args );
        return $obj->driver->direct_remove( $obj, @args );
    }
    else {
        return $obj->driver->remove( $obj, @args );
    }
}

回避方法ですが、とりあえずexists()あたりを使っておけば動くようです。

my $entry = MT->model( 'entry' )->load();

$entry->begin_work;
if ( $entry->exists() ) {      # auto_commit=0
    $entry->remove();          # DELETE ...

    $entry->rollback();        # rollback & auto_commit=1
}