そもそもやりたかったことは、、、
テーブルに対して、DBIC経由でUPDATEなどのDML文が発行された時に、
自動的にmemcachedに保存されているキャッシュを削除させたかったのです。
そうすることで、キャッシュの削除を透過的に行うことができて、嬉しいかなと思いました。
そこで、該当テーブルのupdateメソッドを上書きすることにしました。
package DBIC::DB1::Result::Table;
use strict;
use warnings;
use base 'DBIx::Class';
(中略)
sub update {
my $self = shift;
$self->next::method( @_ );
$self->delete_cache();
}
1;
こんな感じでupdateメソッドを上書きしておけば、UPDATEのタイミングでdelete_cache()も実行されるハズと思っていたのですが、上手くいかない場合がありました。
#!/usr/bin/perl
$ENV{'DBIC_TRACE'} = 1;
use strict;
use warnings;
use lib '/MyAPP/lib/
use YAML::Syck;
use DBIC::DB1;
use utf8;
$YAML::Syck::ImplicitUnicode = 1;
my $configfile = '/MyAPP/MyAPP.yml';
my $c = YAML::Syck::LoadFile($configfile);
my $row = DBIC::DB1->connect(
@{$c->{'Model::DB1'}->{connect_info}}
)->resultset('Table')->find(1);
$row->update({ col1 => '' }); #上書きしたメソッドが実行される
my $rows = DBIC::DB1->connect(
@{$c->{'Model::DB1'}->{connect_info}}
)->resultset('Table')->search({ item_id => { 'in' => ['1','2'] } });
$rows->update({ col1 => '' }); #上書きしたメソッドが実行されない
上記のテストスクリプトを実行すると、findメソッドなどで取得した単一レコードに対してupdateを実行すると、上書きしたupdateメソッドが実行されるのですが、searchメソッドなどで取得した複数行のレコードに対してupdateメソッドを発行した場合、上書きしたupdateメソッド(DBIC::DB1::Result::Table内のupdateメソッド)が呼ばれていないことがわかりました。
そこで、findおよびsearchメソッドが返すオブジェクトを調べてみることにしました。
その結果、findが返すのは、DBIC::DB1::Result::Tableオブジェクト、一方、searchが返すのは、DBIx::Class::ResultSetでした。
そこで、DBIx::Class::ResultSetをGoogle検索したところ、DBIx::Class::Manual::Cookbook - 様々なレシピというページが見つかったので、ここを参考にして次のようなパッケージを新しく作成しました。
package DBIC::DB1::ResultSet::Table;
use strict;
use warnings;
use base 'DBIx::Class::ResultSet';
sub update {
my $self = shift;
$self->next::method( @_ );
$self->delete_cache();
}
1;
そして先ほどのテストスクリプトを実行すると。。。出来た!うまくいきました。
つまり、単一レコード(Result)に対するupdateメソッドと複数レコード(ResultSet)に対するupdateメソッドは、それぞれ別に定義してあげないといけなかったのでした。
なお、先ほどのDBIx::Class::Manual::Cookbook - 様々なレシピというページには、
パッケージ DBIC::DB1::Result::Table に対して、以下のコードを追加するよう書かれていますが、これはなくてもOKでした。
__PACKAGE__->resultset_class('DBIC::DB1::ResultSet::Table');
最初は理由がわからなかったのですが、色々調べてみると自分の環境では、パッケージ DBIC::DB1において、
__PACKAGE__->load_namespaces;
しているからでした。
これをしておくと、DB1/Result、DB1/ResultSet 以下に配置したパッケージが自動的に認識されるみたいです。こりゃ便利。
以下参考にしたURLです。
http://www.mail-archive.com/dbix-class@lists.scsys.co.uk/msg04797.html
http://search.cpan.org/~arcanez/DBIx-Class-0.08126/lib/DBIx/Class/Schema.pm#load_namespaces
http://gihyo.jp/dev/serial/01/perl-hackers-hub/000303
0 件のコメント:
コメントを投稿