データベースにアクセスするようなプログラムを書く時はできるだけSQLを見たくない.接続用のメソッドとかエラーの捕捉用のコードがたくさんあるだけで気分が悪くなってくるほど(言い過ぎ).
やっぱO/Rマッパーでしょ.ちょうどWebDB+PressのバックナンバーのPerlStyleの第2回でClass::DBIのコードを見たので,試してみよう.
次のようなテーブルから一行SELECTする.
CREATE TABLE songs ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, singer TEXT, album TEXT, works TEXT );
いたって普通にDBIを使ってSELECTしてみる.
use strict; use DBI; # SQLiteのデータベースにアクセス my $dbh = DBI->connect("dbi:SQLite:dbname=dbisqlite.db","","", { RaiseError => 1, }) or die $DBI::errstr; # SELECT分一行fetch my $sth = $dbh->prepare('SELECT * FROM songs'); $sth->execute; my $name = $sth->fetchrow_hashref->{name}; $sth->finish; $dbh->disconnect; print "$name\n";
SQLに関係するコードがほとんどできれいじゃないし,わかりにくいことこの上ない.
つぎもまったく同じ出力が得られる.Class::DBIのおまじないを振りかけたコード.
use strict; use Song; my $song = Song->retrieve(1); my $name = $song->name; print "$name\n";
すげー短い.さいこう.メインのロジックとは関係ないSQL関係のコードが完璧に隠蔽されてて,わかりやすいことこの上ない.しかしさすがにタネがあって,Songsクラスを次のように定義する必要があるよう.
package Song; use strict; use warnings; use base qw(Class::DBI); __PACKAGE__->set_db('Main','dbi:SQLite:dbname=dbisqlite.db',"","", { RaiseError => 1, }); __PACKAGE__->table('songs'); __PACKAGE__->columns(Primary => qw(id)); __PACKAGE__->columns(All => qw(name singer album works)); 1;
SQL的な関数も多少はあらわれるけれども,それでもSELECT文は出てこない.Class::DBIのtableというメソッドでテーブル指定して,columnsメソッドで項目の設定をする.すると動的にSongクラスに項目名のメソッドが作成される感じ.かなりスマートだなぁ.あとは,Songsクラスのメソッドを使えばCRUD自由自在.
use strict; use Song; # Insert Song->create({ name => 'オハヨウ', singer => '双葉&梨々&美森', album => 'オハヨウ', works => '吉永さん家のガーゴイル', }) or die "insert fail!"; # Select my $song = Song->search(name => 'オハヨウ'); # Update $song->name('愛においで逢いにおいで'); $song->update; # Delete $song->delete;
RubyだとActiveRecordでもっとクールだよ!とかは言わない.