added experimental expand me...
|
1 |
=encoding utf8 |
2 | ||
updated document
|
3 |
=head1 NAME |
added experimental expand me...
|
4 | |
update pod
|
5 |
DBIx::Custom::Guide::Ja - DBIx::Customのガイドブック |
added experimental expand me...
|
6 | |
7 |
=head1 ガイド |
|
8 | ||
update pod
|
9 |
L<DBIx::Custom>はSQLの実行を簡単に行うためのクラスです。 |
10 |
L<DBIx::Class>やL<DBIx::Simple>と同じように |
|
updated document
|
11 |
L<DBI>のラッパクラスになっています。L<DBIx::Class>よりも簡単に、 |
12 |
L<DBIx::Simple>よりもはるかに柔軟なことを行うことができます。 |
|
added experimental expand me...
|
13 | |
14 |
L<DBIx::Custom>はO/Rマッパーではありません。O/Rマッパーは |
|
15 |
便利ですが、O/Rマッパのたくさんの文法を覚える必要があります。 |
|
updated document
|
16 |
また、O/Rマッパによって生成されたSQLは非効率なことがありますし、 |
17 |
複雑なSQLを生成することができないので、 |
|
18 |
生のSQLを発行しなければならない場合がたくさんあります。 |
|
added experimental expand me...
|
19 | |
updated document
|
20 |
L<DBIx::Custom>はO/Rマッパとは対照的な設計が行われています。 |
updated document
|
21 |
L<DBIx::Custom>の主な目的は、SQLを尊重しつつ、L<DBI>だけでは |
updated document
|
22 |
とてもめんどうな作業を簡単にすることです。もしSQLについて |
23 |
多くの知識を持っているならば、L<DBIx::Custom>でそのまま |
|
updated document
|
24 |
活用することができます。 |
updated document
|
25 | |
update pod
|
26 |
L<DBIx::Custom>の仕組みを少しだけ説明しておきます。 |
updated document
|
27 |
L<DBIx::Custom>では、タグと呼ばれるものを |
28 |
SQLの中に埋め込むことができます。 |
|
29 | ||
30 |
select * from book where {= title} and {=author}; |
|
31 | ||
32 |
{}で囲まれた部分がタグです。このSQLは実際に実行されるときには |
|
33 |
次のようにプレースホルダに展開されます。 |
|
34 | ||
updated document
|
35 |
select * from book where title = ? and author = ?; |
updated document
|
36 | |
37 |
これらの展開にはどのような意味があるのでしょうかと質問 |
|
update pod
|
38 |
されるかもしれません。この簡単な仕組みの上に |
39 |
便利な機能が実装されます。それは以下のようなものです。 |
|
updated document
|
40 | |
updated document
|
41 |
=over 4 |
updated document
|
42 | |
update pod
|
43 |
=item 1. プレースホルダにバインドする値をハッシュリファレンスで指定 |
updated document
|
44 | |
update pod
|
45 |
L<DBI>を使うのであればプレースホルダにバインドする値は配列 |
updated document
|
46 |
で指定する必要があります。 |
updated document
|
47 | |
updated document
|
48 |
$sth->execute(@bind); |
49 | ||
50 |
L<DBIx::Custom>を利用するのであればハッシュリファレンスで指定すること |
|
51 |
できます。 |
|
52 |
|
|
53 |
my $param = {title => 'Perl', author => 'Ken'}; |
|
54 |
$dbi->execute($sql, $param); |
|
55 | ||
update pod
|
56 |
=item 2. 値のフィルタリング |
updated document
|
57 | |
update pod
|
58 |
L<DBIx::Custom>はフィルタリングの機能を提供します。 |
updated document
|
59 |
たとえば、日付の列は、Perlで扱うときにはC<Time::Piece>などの日付オブジェクト |
60 |
で扱い、データベースに格納するときはデータベースの日付型に変換したい |
|
61 |
と思うのではないでしょうか。またデータベースから取り出すときは |
|
62 |
データベースの日付型から日付オブジェクトに変換したと思うのでは |
|
63 |
ないでしょうか。 |
|
64 | ||
65 |
このようなときはフィルタ機能を使うことができます。 |
|
66 | ||
67 |
まずフィルタを登録します。 |
|
68 | ||
69 |
$dbi->register_filter( |
|
70 |
tp_to_date => sub { |
|
71 |
... |
|
72 |
}, |
|
73 |
date_to_tp => sub { |
|
74 |
... |
|
75 |
} |
|
76 |
); |
|
77 | ||
78 |
次にテーブルの各列にこのフィルタを適用します。 |
|
79 | ||
80 |
$dbi->apply_filter('book', |
|
renamed dbi_options to dbi_o...
|
81 |
'issue_date' => {out => 'tp_to_date', in => 'date_to_tp'} |
updated document
|
82 |
); |
83 | ||
84 |
outはPerlからデータベースに保存する方向、inはデータベースからPerlに取得する方向です。 |
|
85 | ||
update pod
|
86 |
多くのメソッドで自動的にこのフィルタが有効になります。 |
updated document
|
87 | |
update pod
|
88 |
$dbi->insert(table => 'book', param => {issue_date => $tp}); |
updated document
|
89 | |
90 |
=item 3. 選択的な検索条件 |
|
91 | ||
update pod
|
92 |
L<DBI>では選択的に検索条件を作成することは難しいです。 |
updated document
|
93 | |
94 |
たとえば、検索条件にtitleとauthorが指定された場合は次のSQLを |
|
95 | ||
96 |
select * from book where title = ? and author = ?; |
|
97 | ||
98 |
titleだけの場合は次のSQLを |
|
99 | ||
100 |
select * from book where title = ?; |
|
101 |
|
|
102 |
authorだけの場合は次のSQLを発行した場合を考えましょう。 |
|
103 | ||
104 |
select * from book where author = ?; |
|
105 | ||
106 |
これはとても大変な作業なので、通常はL<SQL::Abstract>を動的に生成してくれる |
|
107 |
モジュールを利用することになります。 |
|
108 | ||
109 |
L<DBIx::Custom>はさらに簡単で便利な方法を用意しています。 |
|
110 | ||
update pod
|
111 |
# Whereオブジェクト |
updated document
|
112 |
my $where = $dbi->where; |
update pod
|
113 |
|
114 |
# 検索条件 |
|
updated document
|
115 |
$where->clause( |
116 |
['and', '{= title}', {'= author'}] |
|
117 |
); |
|
update pod
|
118 |
|
119 |
# 必要な列を自動的に選択するための設定 |
|
120 |
$where->param({title => 'Perl'}); |
|
updated document
|
121 | |
update pod
|
122 |
# SQLへのWhere句の埋め込み |
updated document
|
123 |
my $sql = "select * from book $where"; |
124 | ||
125 |
詳しい説明は後ほど行いますが、上記のように記述すれば、 |
|
126 |
L<DBIx::Custom>では選択的な検索条件を持つWhere句を生成することができます。 |
|
127 |
検索条件が入れ子になった構造やorについても対応しています。 |
|
128 | ||
129 |
=item 4. 挿入、更新、削除、選択を行うためのメソッド |
|
130 | ||
131 |
L<DBIx::Custom>ではSQLをさらに簡単に実行するための |
|
132 |
メソッドも提供しています。 |
|
added experimental expand me...
|
133 |
C<insert()>, C<update()>, C<delete()>,C<select()>などの |
updated document
|
134 |
シュガーメソッドを使って、挿入、更新、削除、選択という操作を行うことが |
135 |
できます。 |
|
136 | ||
137 |
my $param = {title => 'Perl', author => 'Ken'}; |
|
138 |
$dbi->insert(table => 'book', param => $param); |
|
139 | ||
140 |
=item 5. テーブル単位の操作の登録 |
|
141 | ||
142 |
テーブルに対して操作を登録することができます。これによって |
|
143 |
テーブル名を繰り返し指定する必要がなくなり、ソースコードの |
|
144 |
見通しが良くなります。 |
|
145 | ||
146 |
$dbi->talbe('book', |
|
147 |
list => sub { |
|
148 |
... |
|
149 |
}, |
|
150 |
list_somethin => sub { |
|
151 |
|
|
152 |
} |
|
153 |
); |
|
154 | ||
155 |
登録したメソッドはそのまま利用することができます。 |
|
156 | ||
157 |
$dbi->table('book')->list; |
|
added experimental expand me...
|
158 | |
updated document
|
159 |
通常O/Rマッパはテーブルに対応するクラスを作成しなければ |
160 |
ならないことが多いですが、L<DBIx::Custom>ではこの作業を簡便に |
|
161 |
しており、上記のように登録することができます。 |
|
added experimental expand me...
|
162 | |
updated document
|
163 |
=back |
164 | ||
165 |
L<DBIx::Custom>はL<DBI>を補うとても便利なモジュールです。 |
|
166 |
興味をもたれた方は、この後で詳しい解説を行いますので、 |
|
167 |
ご覧になってみてください。 |
|
added experimental expand me...
|
168 | |
169 |
=head2 1. データベースへの接続 |
|
170 | ||
updated document
|
171 |
まずL<DBIx::Custom>を読み込みます。 |
172 | ||
173 |
use DBIx::Custom; |
|
174 | ||
added experimental expand me...
|
175 |
L<DBIx::Custom>オブジェクトを生成し、データベースに接続するには |
176 |
C<connect()>メソッドを使用します。 |
|
177 | ||
updated document
|
178 |
my $dbi = DBIx::Custom->connect( |
179 |
data_source => "dbi:mysql:database=dbname", |
|
180 |
user => 'ken', |
|
181 |
password => '!LFKD%$&', |
|
182 |
dbi_options => {mysql_enable_utf8 => 1} |
|
183 |
); |
|
added experimental expand me...
|
184 | |
updated document
|
185 |
C<data_source>はデータベースシステムに応じたフォーマットで |
186 |
指定する必要があります。以下にデータベースごとのフォーマット |
|
187 |
方法のサンプルを掲載しておきます。 |
|
added experimental expand me...
|
188 | |
updated document
|
189 |
B<MySQL> |
added experimental expand me...
|
190 | |
deprecated DBIx::Custom::MyS...
|
191 |
"dbi:mysql:database=$database" |
192 |
"dbi:mysql:database=$database;host=$hostname;port=$port" |
|
added experimental expand me...
|
193 | |
updated document
|
194 |
B<SQLite> |
deprecated DBIx::Custom::MyS...
|
195 | |
196 |
"dbi:SQLite:dbname=$database" |
|
197 |
"dbi:SQLite:dbname=:memory:" |
|
198 | ||
updated document
|
199 |
B<PostgreSQL> |
deprecated DBIx::Custom::MyS...
|
200 | |
201 |
"dbi:Pg:dbname=$dbname" |
|
202 | ||
updated document
|
203 |
B<Oracle> |
deprecated DBIx::Custom::MyS...
|
204 | |
205 |
"dbi:Oracle:$dbname" |
|
206 |
"dbi:Oracle:host=$host;sid=$sid" |
|
207 | ||
updated document
|
208 |
B<ODBC(Microsoft Access)> |
deprecated DBIx::Custom::MyS...
|
209 | |
210 |
"dbi:ODBC:driver=Microsoft Access Driver (*.mdb);dbq=hoge.mdb" |
|
211 | ||
updated document
|
212 |
B<ODBC(SQL Server)> |
deprecated DBIx::Custom::MyS...
|
213 | |
214 |
"dbi:ODBC:driver={SQL Server};Server=(local);database=test;Trusted_Connection=yes;AutoTranslate=No;" |
|
added experimental expand me...
|
215 | |
updated document
|
216 |
また認証が求められる場合は、C<user>とC<password>ユーザ名と |
217 |
パスワードを指定する必要があります。 |
|
218 | ||
added experimental expand me...
|
219 |
L<DBIx::Custom>はL<DBI>のラッパです。 |
updated document
|
220 |
L<DBI>のデータベースハンドルはC<dbh>で取得することができます。 |
added experimental expand me...
|
221 | |
222 |
my $dbh = $dbi->dbh; |
|
223 | ||
updated document
|
224 |
L<DBIx::Custom>ではデータベースハンドル属性にはデフォルトで次のものが設定されます。 |
added experimental expand me...
|
225 |
|
226 |
$dbi->dbh->{RaiseError} = 1; |
|
227 |
$dbi->dbh->{PrintError} = 0; |
|
228 |
$dbi->dbh->{AutoCommit} = 1; |
|
229 | ||
230 |
この設定を行っているので、致命的なエラーが起こると、 |
|
231 |
例外が発生しプログラムは終了します。 |
|
232 |
またクエリが発行されると自動的にコミットされます。 |
|
233 | ||
updated document
|
234 |
=head2 2. 挿入、更新、削除、選択のためのメソッド |
added experimental expand me...
|
235 | |
236 |
L<DBIx::Custom>は、 |
|
237 |
C<insert()>、C<update()>、C<delete()>、C<select()> |
|
updated document
|
238 |
のような挿入、更新、削除、選択を行うためのメソッドを持っています。 |
239 |
簡単なことをを行うのであれば、SQLを自分で記述する必要がありません。 |
|
added experimental expand me...
|
240 | |
update pod
|
241 |
=head3 データの挿入 C<insert()> |
added experimental expand me...
|
242 | |
updated document
|
243 |
データベースにデータを挿入するにはC<insert()>を使用します。 |
added experimental expand me...
|
244 | |
remove DBIx::Custom::Model
|
245 |
$dbi->insert(table => 'book', |
added experimental expand me...
|
246 |
param => {title => 'Perl', author => 'Ken'}); |
247 | ||
updated document
|
248 |
C<table>にはテーブル名、C<param>には挿入したいデータを指定します。 |
added experimental expand me...
|
249 | |
updated document
|
250 |
次のSQLが発行されます。 |
251 | ||
252 |
insert into (title, author) values (?, ?); |
|
added experimental expand me...
|
253 | |
update pod
|
254 |
=head3 データの更新 C<update()> |
added experimental expand me...
|
255 | |
updated document
|
256 |
データベースのデータを更新するには、C<update()>を使用します。 |
added experimental expand me...
|
257 | |
remove DBIx::Custom::Model
|
258 |
$dbi->update(table => 'book', |
added experimental expand me...
|
259 |
param => {title => 'Perl', author => 'Ken'}, |
260 |
where => {id => 5}); |
|
261 | ||
updated document
|
262 |
C<table>にはテーブル名、C<param>には挿入したいデータ、C<where>には |
263 |
条件を指定します。 |
|
added experimental expand me...
|
264 | |
updated document
|
265 |
次のSQLが発行されます。 |
266 | ||
267 |
update book set title = ?, author = ?; |
|
added experimental expand me...
|
268 | |
269 |
C<update>メソッドは安全のため |
|
270 |
where句のないSQLを発行することを許可していません。 |
|
271 |
もしすべての行を更新したい場合は |
|
updated document
|
272 |
C<update_all()>を使用してください。 |
added experimental expand me...
|
273 | |
remove DBIx::Custom::Model
|
274 |
$dbi->update_all(table => 'book', |
added experimental expand me...
|
275 |
param => {title => 'Perl', author => 'Ken'}); |
276 | ||
update pod
|
277 |
=head3 データの削除 C<delete()> |
added experimental expand me...
|
278 | |
updated document
|
279 |
データベースのデータを1件削除するには、C<delete()>を使用します。 |
added experimental expand me...
|
280 | |
remove DBIx::Custom::Model
|
281 |
$dbi->delete(table => 'book', |
added experimental expand me...
|
282 |
where => {author => 'Ken'}); |
283 | ||
updated document
|
284 |
C<table>にはテーブル名、C<where>には条件を指定します。 |
added experimental expand me...
|
285 | |
updated document
|
286 |
次のSQLが発行されます。 |
287 | ||
288 |
delete from book where id = ?; |
|
added experimental expand me...
|
289 | |
290 |
C<delete>メソッドは安全のため |
|
291 |
where句のないSQLを発行することを許可していません。 |
|
292 |
もしすべての行を削除したい場合は |
|
updated document
|
293 |
C<delete_all()>を使用してください。 |
added experimental expand me...
|
294 | |
remove DBIx::Custom::Model
|
295 |
$dbi->delete_all(table => 'book'); |
added experimental expand me...
|
296 | |
update pod
|
297 |
=head3 データの選択 C<select()> |
added experimental expand me...
|
298 | |
updated document
|
299 |
行を選択するにはC<select()>を使用します。 |
added experimental expand me...
|
300 | |
remove DBIx::Custom::Model
|
301 |
my $result = $dbi->select(table => 'book'); |
added experimental expand me...
|
302 | |
updated document
|
303 |
C<table>だけを指定して、他の条件を指定しない場合は次のSQLが発行されます。 |
added experimental expand me...
|
304 | |
updated document
|
305 |
select * from book; |
added experimental expand me...
|
306 | |
307 |
C<select()>メソッドの戻り値はL<DBIx::Custom::Result> |
|
updated document
|
308 |
オブジェクトです。行をフェッチするにはC<fetch()>を使用します。 |
added experimental expand me...
|
309 | |
310 |
while (my $row = $result->fetch) { |
|
311 |
my $title = $row->[0]; |
|
312 |
my $author = $row->[1]; |
|
313 |
} |
|
314 | ||
updated document
|
315 |
L<DBIx::Custom::Result>についてはこの後L<3. 行のフェッチ/"3. 行のフェッチ">で詳しく扱います。 |
316 | ||
317 |
さまざまなC<select()>の使い方を見ていきましょう。 |
|
added experimental expand me...
|
318 |
次のC<select>は行の名前とwhere句を指定したものです。 |
319 | ||
320 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
321 |
table => 'book', |
updated document
|
322 |
column => ['author', 'title'], |
added experimental expand me...
|
323 |
where => {author => 'Ken'} |
324 |
); |
|
325 | ||
updated document
|
326 |
C<column>には列名を、C<where>には条件を指定することができます。 |
327 |
次のSQLが発行されます。 |
|
328 | ||
329 |
select author, title from book where author = ?; |
|
added experimental expand me...
|
330 | |
updated document
|
331 |
テーブルを結合したい場合ははC<relation>にテーブルの |
332 |
関係を記述します。 |
|
added experimental expand me...
|
333 | |
334 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
335 |
table => ['book', 'rental'], |
updated document
|
336 |
where => {book.name => 'Perl'}, |
remove DBIx::Custom::Model
|
337 |
relation => {'book.id' => 'rental.book_id'} |
added experimental expand me...
|
338 |
); |
339 | ||
updated document
|
340 |
bookテーブルのid列とrentalテーブルのbook_idが関連付けられます。 |
341 |
次のSQLが発行されます。 |
|
added experimental expand me...
|
342 | |
updated document
|
343 |
select * from book, rental where book.name = ? and book.id = rental.book_id; |
added experimental expand me...
|
344 | |
updated document
|
345 |
SQL文の末尾に文字列を追加したい場合は<append>を使用します。 |
added experimental expand me...
|
346 | |
347 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
348 |
table => 'book', |
added experimental expand me...
|
349 |
where => {author => 'Ken'}, |
updated document
|
350 |
append => 'for update', |
added experimental expand me...
|
351 |
); |
352 | ||
updated document
|
353 |
次のSQLが発行されます。 |
updated document
|
354 | |
updated document
|
355 |
select * book where author = ? for update; |
updated document
|
356 | |
updated document
|
357 |
またC<append>は、C<select>だけでなくC<insert()>、C<update()>、C<update_all()> |
358 |
C<delete()>、C<delete_all()>、C<select()>で使用することもできます。 |
|
updated document
|
359 | |
update pod
|
360 |
=head3 SQLの実行 C<execute()> |
removed experimental txn_sco...
|
361 | |
362 |
任意のSQLを実行するにはexecuteメソッドを使用します。 |
|
363 | ||
364 |
$dbi->execute("select * from book;"); |
|
365 | ||
366 |
C<execute()>はL<DBIx::Custom>の根幹のメソッドでありタグを展開します。 |
|
367 | ||
368 |
$dbi->execute( |
|
369 |
"select * from book {= title} and {= author};" |
|
370 |
param => {title => 'Perl', author => 'Ken'} |
|
371 |
); |
|
372 | ||
373 |
上記のタグを含んだSQLは次のように展開されます。 |
|
374 | ||
375 |
select * from book title = ? and author = ?; |
|
376 | ||
377 |
SQLが実行されるときにプレースホルダ(?)に対応する位置にtitleとauthor |
|
378 |
の値がが自動的に埋め込まれます。 |
|
379 | ||
380 |
タグについてはL<5. タグ/"5. タグ">で詳しく解説しますが、 |
|
381 |
ひとつの注意点があります。 |
|
382 |
タグを展開するためにC<{>とC<}>は予約語になっています。 |
|
383 |
もし利用したい場合は直前に\をおいてエスケープを行う必要があります。 |
|
384 | ||
385 |
$dbi->execute("... \\{ ... \\} ..."); |
|
386 | ||
387 |
\自体がPerlのエスケープ文字ですので、二つ必要になるという点に注意してください。 |
|
388 | ||
389 |
またexecuteのキュートな機能として、SQLの最後にセミコロンをおかなくても |
|
390 |
かまいません。 |
|
391 | ||
392 |
$dbi->execute('select * from book'); |
|
393 | ||
updated document
|
394 |
=head2 3. 行のフェッチ |
395 | ||
updated document
|
396 |
C<select()>メソッドの戻り値はL<DBIx::Custom::Result>オブジェクトです。 |
397 |
L<DBIx::Custom::Result>には行をフェッチするためのさまざまなメソッドが |
|
updated document
|
398 |
用意されています。 |
399 | ||
update pod
|
400 |
=head3 1行づつフェッチ(配列) C<fetch()> |
updated document
|
401 | |
updated document
|
402 |
一行フェッチして配列のリファレンスに格納するにはC<fetch()>を使用します。 |
updated document
|
403 | |
404 |
while (my $row = $result->fetch) { |
|
updated document
|
405 |
my $title = $row->[0]; |
406 |
my $author = $row->[1]; |
|
updated document
|
407 |
} |
408 | ||
updated document
|
409 |
whileループを使って、すべての行を取得することができます。 |
410 | ||
update pod
|
411 |
=head3 最初の行だけフェッチ(配列) C<fetch_first()> |
updated document
|
412 | |
updated document
|
413 |
一行だけフェッチして配列のリファレンスに格納するにはC<fetch_first()> |
414 |
を使用します。 |
|
updated document
|
415 | |
416 |
my $row = $result->fetch_first; |
|
417 | ||
updated document
|
418 |
一行のフェッチが終わった後はそれ以上フェッチできなくなります。 |
419 |
内部的には1行のフェッチが終わった後に |
|
420 |
ステートメントハンドルのC<finish()>が実行されます。 |
|
updated document
|
421 | |
update pod
|
422 |
=head3 複数行を順にフェッチ(配列) C<fetch_multi()> |
updated document
|
423 | |
updated document
|
424 |
複数行をフェッチして配列のリファレンスを要素に持つ |
425 |
配列のリファレンスに格納するにはC<fetch_multi()>を使用します。 |
|
updated document
|
426 | |
updated document
|
427 |
while (my $rows = $result->fetch_multi(2)) { |
428 |
my $title0 = $rows->[0][0]; |
|
429 |
my $author0 = $rows->[0][1]; |
|
430 |
|
|
431 |
my $title1 = $rows->[1][0]; |
|
432 |
my $author1 = $rows->[1][1]; |
|
updated document
|
433 |
} |
434 | ||
updated document
|
435 |
引数には取り出したい行数を指定します。 |
436 | ||
437 |
指定した行を格納した次のようなデータを取得できます。 |
|
438 | ||
439 |
[ |
|
440 |
['Perl', 'Ken'], |
|
441 |
['Ruby', 'Mark'] |
|
442 |
] |
|
443 | ||
update pod
|
444 |
=head3 すべての行をフェッチ(配列) C<fetch_all> |
updated document
|
445 | |
updated document
|
446 |
すべての行をフェッチして配列のリファレンスを要素に持つ |
447 |
配列のリファレンスに格納するにはC<fetch_all()>を使用します。 |
|
updated document
|
448 | |
449 |
my $rows = $result->fetch_all; |
|
450 | ||
updated document
|
451 |
すべての行を格納した次のようなデータを取得できます。 |
452 | ||
453 |
[ |
|
454 |
['Perl', 'Ken'], |
|
455 |
['Ruby', 'Mark'] |
|
456 |
] |
|
457 | ||
update pod
|
458 |
=head3 1行づつフェッチ(ハッシュ) C<fetch_hash()> |
updated document
|
459 | |
updated document
|
460 |
一行フェッチしてハッシュのリファレンスに格納するにはC<fetch_hash()>を使用します。 |
updated document
|
461 | |
462 |
while (my $row = $result->fetch_hash) { |
|
463 |
my $title = $row->{title}; |
|
464 |
my $author = $row->{author}; |
|
465 |
} |
|
466 | ||
update pod
|
467 |
=head3 最初の行だけフェッチ(ハッシュ) C<fetch_hash_first()> |
updated document
|
468 | |
updated document
|
469 |
一行だけフェッチしてハッシュのリファレンスに格納するには |
470 |
C<fetch_hash_first()>を使用します。 |
|
updated document
|
471 | |
472 |
my $row = $result->fetch_hash_first; |
|
473 | ||
updated document
|
474 |
一行のフェッチが終わった後はそれ以上フェッチできなくなります。 |
475 |
内部的には1行のフェッチが終わった後に |
|
476 |
ステートメントハンドルのC<finish()>が実行されます。 |
|
updated document
|
477 | |
update pod
|
478 |
=head3 複数行を順にフェッチ(ハッシュ) C<fetch_hash_multi()> |
updated document
|
479 | |
updated document
|
480 |
複数行をフェッチしてハッシュのリファレンスを要素に持つ |
481 |
配列のリファレンスに格納するにはC<fetch_hash_multi()> |
|
482 |
を使用します。 |
|
updated document
|
483 | |
484 |
while (my $rows = $result->fetch_hash_multi(5)) { |
|
updated document
|
485 |
my $title0 = $rows->[0]{title}; |
486 |
my $author0 = $rows->[0]{author}; |
|
487 |
my $title1 = $rows->[1]{title}; |
|
488 |
my $author1 = $rows->[1]{author}; |
|
updated document
|
489 |
} |
490 | ||
updated document
|
491 |
引数には取り出したい行数を指定します。 |
492 | ||
493 |
指定した行を格納した次のようなデータを取得できます。 |
|
494 | ||
495 |
[ |
|
496 |
{title => 'Perl', author => 'Ken'}, |
|
497 |
{title => 'Ruby', author => 'Mark'} |
|
498 |
] |
|
499 | ||
update pod
|
500 |
=head3 すべての行をフェッチ(ハッシュ) C<fetch_hash_all()> |
updated document
|
501 | |
updated document
|
502 |
すべての行をフェッチしてハッシュのリファレンスを要素に持つ |
503 |
配列のリファレンスに格納するにはC<fetch_hash_all()> |
|
504 |
を使用します。 |
|
updated document
|
505 | |
506 |
my $rows = $result->fetch_hash_all; |
|
507 | ||
updated document
|
508 |
すべての行を格納した次のようなデータを取得できます。 |
509 | ||
510 |
[ |
|
511 |
{title => 'Perl', author => 'Ken'}, |
|
512 |
{title => 'Ruby', author => 'Mark'} |
|
513 |
] |
|
514 | ||
update pod
|
515 |
=head3 ステートメントハンドル C<sth()> |
updated document
|
516 | |
517 |
ステートメントハンドルに直接アクセスしたい場合は |
|
518 |
<sth>で取得することができます。 |
|
updated document
|
519 | |
520 |
my $sth = $result->sth; |
|
521 | ||
updated document
|
522 |
フェッチのパフォーマンスが用件を満たさないときには、 |
523 |
ステートメントハンドルから |
|
524 |
利用できる速度の速いメソッドを利用することができます。 |
|
525 | ||
renamed dbi_options to dbi_o...
|
526 |
=head2 4. フィルタリング |
527 | ||
528 |
データベースにデータを登録するときやデータベースからデータを取得する |
|
529 |
ときに自動的に値の変換を行いたい場合が多いと思います。 |
|
530 |
たとえば、日付を表現する列の場合は、 |
|
531 |
データベースに登録する場合はL<Time::Piece>オブジェクトから |
|
532 |
データベースの日付のフォーマットに、 |
|
533 |
データベースからデータを取得するときは、その逆を行えると便利です。 |
|
534 | ||
update pod
|
535 |
=head3 フィルタの登録 C<register_filter()> |
renamed dbi_options to dbi_o...
|
536 | |
537 |
フィルタを登録するにはC<register_filter()>を使用します。 |
|
538 | ||
539 |
$dbi->register_filter( |
|
540 |
# Time::Piece object to DATE format |
|
541 |
tp_to_date => sub { |
|
542 |
my $date = shift; |
|
543 | ||
544 |
return '0000-00-00' unless $tp; |
|
545 |
return $tp->strftime('%Y-%m-%d'); |
|
546 |
}, |
|
547 |
|
|
548 |
# DATE to Time::Piece object |
|
549 |
date_to_tp => sub { |
|
550 |
my $date = shift; |
|
551 | ||
552 |
return if $date eq '0000-00-00'; |
|
553 |
return Time::Piece->strptime($date, '%Y-%m-%d'); |
|
554 |
}, |
|
555 |
); |
|
556 | ||
557 |
登録したフィルタはC<apply_filter()>などで利用することができます。 |
|
558 | ||
update pod
|
559 |
=head3 フィルタの適用 C<apply_filter()> |
renamed dbi_options to dbi_o...
|
560 | |
561 |
作成したフィルタを適用するには、C<apply_filter()>を使用します。 |
|
562 | ||
563 |
$dbi->apply_filter('book', |
|
564 |
issue_date => {out => 'tp_to_date', in => 'date_to_tp'}, |
|
565 |
first_issue_date => {out => 'tp_to_date', in => 'date_to_tp'} |
|
566 |
); |
|
567 | ||
568 |
第一引数はテーブル名です。第二引数以降は、列名とフィルタルールのペアを記述します。 |
|
569 |
フィルタルールのoutには、データベースにデータを送信するときに適用するフィルタを、 |
|
570 |
フィルタルールのinには、データベースからデータを取得するときに適用するフィルタを |
|
571 |
記述します。outがデータベースに送信する方向、inがデータベースから取り出す方向です。 |
|
572 |
フィルタには、C<register_filter>で登録したフィルタ名の他に、コードリファレンスを |
|
573 |
指定することもできます。 |
|
574 | ||
575 |
issue_date => {out => sub { ... }, in => sub { ... }} |
|
576 | ||
577 |
適用されたフィルタはC<insert()>、C<update()>、C<update_all()>、C<delete()>、 |
|
578 |
C<delete_all()>、C<select()>で有効になります。 |
|
579 | ||
580 |
my $tp = Time::Piece->strptime('2010/10/14', '%Y/%m/%d'); |
|
581 |
my $result = $dbi->select(table => 'book', where => {issu_date => $tp}); |
|
582 | ||
583 |
データベースにデータが送信されるときに、L<Time::Piece>オブジェクトは |
|
584 |
データベースの日付のフォーマット「2010-10-14」に変換されます。 |
|
585 | ||
586 |
また逆にデータをフェッチするときには、データベースの日付のフォーマットは |
|
587 |
タイムピースオブジェクトに変換されます。 |
|
588 | ||
589 |
my $row = $resutl->fetch_hash_first; |
|
590 |
my $tp = $row->{issue_date}; |
|
591 | ||
592 |
このような自動的に実行されるフィルタを登録できることがL<DBIx::Custom>の |
|
593 |
特徴のひとつです。 |
|
594 | ||
removed experimental expand
|
595 |
C<apply_filter()>で適用されたフィルタはテーブル名をを含む列名に対しても有効です。 |
596 | ||
597 |
$dbi->select( |
|
598 |
table => 'book', |
|
599 |
where => {'book.title' => 'Perl', 'book.author' => 'Ken'} |
|
600 |
); |
|
601 | ||
602 |
テーブルを区別する必要があるときに便利な機能です。 |
|
603 | ||
update pod
|
604 |
=head3 個別のフィルタの適用 C<filter> |
renamed dbi_options to dbi_o...
|
605 | |
606 |
C<apply_filter()>を使って最初にすべてのテーブルの列について |
|
removed experimental txn_sco...
|
607 |
フィルタを定義することもできますが、 |
608 |
個別にフィルタを適用することもできます。 |
|
renamed dbi_options to dbi_o...
|
609 |
個別のフィルタはC<apply_filter()>で適用したフィルタを上書きます。 |
removed experimental txn_sco...
|
610 |
個別のフィルタはSQLのasを使って、列の別名を作成する必要がある場合に活躍します。 |
611 | ||
612 |
データベースに送信する場合に、個別のフィルタを適用するには、各メソッドの |
|
613 |
C<filter>オプションを使用します。個別のフィルタは、C<insert()>、C<update()>、 |
|
614 |
C<update_all()>、C<delete()>、C<delete_all()>、C<select()>、C<execute()> |
|
615 |
で使用することができます。 |
|
renamed dbi_options to dbi_o...
|
616 | |
removed experimental txn_sco...
|
617 |
C<insert()>の例を示します。 |
618 | ||
619 |
$dbi->insert( |
|
620 |
table => 'book', |
|
621 |
param => {issue_date => $tp, first_issue_date => $tp}, |
|
622 |
filter => {issue_date => 'tp_to_date', first_issue_date => 'tp_to_date'} |
|
623 |
); |
|
624 | ||
625 |
C<execute()>の例を示します。 |
|
626 | ||
627 |
my $sql = <<"EOS"; |
|
628 |
select YEAR(issue_date) as issue_year |
|
629 |
from book |
|
630 |
where YEAR(issue_date) = {? issue_year} |
|
631 |
EOS |
|
632 |
|
|
633 |
my $result = $dbi->execute( |
|
634 |
$sql, |
|
635 |
param => {issue_year => '2010'}, |
|
636 |
filter => {issue_year => 'tp_to_year'} |
|
637 |
); |
|
638 | ||
639 |
これはC<filter>を使う良くある例です。issue_dateの変換についてはC<apply_filter()> |
|
640 |
で登録してあるのですが、新しく作成した列であるissue_yearについては、 |
|
641 |
何の変換も登録されていません。ですので、個別にフィルタを設定しています。 |
|
642 | ||
643 |
また反対に行をフェッチするときにも個別のフィルタを適用することができます。 |
|
644 |
フィルタを適用するには、 |
|
renamed dbi_options to dbi_o...
|
645 |
C<DBIx::Custom::Result>クラスのC<filter>メソッドを使用します。 |
646 | ||
removed experimental txn_sco...
|
647 |
$result->filter(issue_year => 'year_to_tp'); |
648 | ||
649 |
頻繁に利用するのであれば、個別に登録するよりもC<apply_filter()>で登録 |
|
650 |
しておいたほうが便利でしょう。C<apply_filter()>は存在しない列に対しても |
|
651 |
フィルタを適用できるからです。 |
|
652 | ||
653 |
$dbi->apply_filter('book', |
|
654 |
'issue_year' => {out => 'tp_to_year', in => 'year_to_tp'} |
|
655 |
); |
|
656 | ||
update pod
|
657 |
=head3 最終出力のためのフィルタリング C<end_filter()> |
658 | ||
removed experimental txn_sco...
|
659 |
C<DBIx::Custom::Result>ではさらに最後にもう一度、フィルタを追加で |
660 |
登録することができます。たとえばHTMLに出力したい場合に、Time::Piece |
|
661 |
オブジェクトから読みやすい記述に変換することができます。 |
|
662 |
最後のフィルタを登録するには、C<end_filter()>を使用します。 |
|
663 | ||
664 |
$result->end_filter(issue_date => sub { |
|
665 |
my $tp = shift; |
|
666 |
|
|
667 |
return '' unless $tp; |
|
668 |
return $tp->strftime('%Y/%m/%d %h:%m:%s (%a)'); |
|
669 |
}); |
|
670 | ||
671 |
日付を見やすい形にフォーマットすることができます。 |
|
672 | ||
673 |
フィルタはフェッチを行う前に登録しておく必要があることに |
|
674 |
注意してください。 |
|
675 | ||
676 |
$result->filter(...); |
|
677 |
$result->end_filter(...); |
|
678 |
my $row = $result->fetch_hash_first; |
|
679 | ||
update pod
|
680 |
=head3 列の情報を元にフィルタを適用する C<each_column()> |
removed experimental txn_sco...
|
681 | |
682 |
日付型の列は手動で設定しなくても、自動的に設定できると便利です。 |
|
683 |
このためにデータベースのテーブルの列のすべての情報を |
|
684 |
順番に処理するためのC<each_column()>があります。 |
|
685 | ||
686 |
$dbi->each_column( |
|
687 |
sub { |
|
688 |
my ($self, $table, $column, $info) = @_; |
|
689 |
|
|
690 |
my $type = $info->{TYPE_NAME}; |
|
691 |
|
|
692 |
my $filter = $type eq 'DATE' ? {out => 'tp_to_date', in => 'date_to_tp'} |
|
693 |
: $type eq 'DATETIME' ? {out => 'tp_to_datetime', in => 'datetime_to_tp'} |
|
694 |
: undef; |
|
695 |
|
|
696 |
$self->apply_filter($table, $column, $filter) |
|
697 |
if $filter; |
|
698 |
} |
|
699 |
); |
|
renamed dbi_options to dbi_o...
|
700 | |
removed experimental txn_sco...
|
701 |
each_columnはコールバックを受け取ります。コールバックの引数は |
702 |
順番にL<DBIx::Custom>オブジェクト、テーブル名、列名、列の情報です。 |
|
703 |
列の型名の情報をもとに自動的に、フィルタを適用しています。 |
|
704 | ||
705 |
ひとつの注意点としてコールバックの中から、コールバックの外側 |
|
706 |
の変数を参照しないように注意してください。each_columnは |
|
707 |
高々1回だけ実行されるだけなので、ほとんどの場合問題ありませんが、 |
|
708 |
循環参照によるメモリリークが発生してしまう可能性を持っているからです。 |
|
renamed dbi_options to dbi_o...
|
709 | |
710 |
=head2 5. タグ |
|
updated document
|
711 | |
update pod
|
712 |
=head3 タグの機能 |
updated document
|
713 | |
update pod
|
714 |
L<DBIx::Custom>はSQLの中にタグを埋め込む機能を持っています。 |
updated document
|
715 | |
update pod
|
716 |
select * from book where {= title} and {like author}; |
updated document
|
717 | |
update pod
|
718 |
{= title}と{like author}の部分がタグです。タグは次のような形式 |
719 |
を持ちます。 |
|
updated document
|
720 | |
update pod
|
721 |
{タグ名 引数1 引数2 ...} |
722 |
|
|
723 |
タグはC<{>で始まり、C<}>で終わります。最初のC<{>とタグ名の間 |
|
724 |
には空白を挿入しないよう注意してください。 |
|
updated document
|
725 | |
update pod
|
726 |
タグの機能のためにC<{>とC<}>は予約語になっています。 |
727 |
もし利用したい場合は直前に\をおいてエスケープを行う必要があります。 |
|
updated document
|
728 | |
update pod
|
729 |
select from book \\{ ... \\} |
730 | ||
731 |
C<\>自体がPerlのエスケープ文字ですので、 |
|
732 |
エスケープする場合はC<\>が二つ必要になるという点に注意してください。 |
|
733 | ||
734 |
上記のタグはSQLが実行される前に次のSQLに展開されます。 |
|
735 | ||
736 |
select * from book where title = ? and author like ?; |
|
updated document
|
737 | |
update pod
|
738 |
タグを含むSQLを実行するにはC<execute()>を使用します。 |
updated document
|
739 | |
update pod
|
740 |
my $sql = "select * from book where {= author} and {like title};" |
741 |
$dbi->execute($sql, param => {title => 'Perl', author => '%Ken%'}); |
|
updated document
|
742 | |
update pod
|
743 |
C<param>オプションを使って、プレースホルダに埋め込みたい値を |
744 |
ハッシュリファレンスで指定することができます。 |
|
updated document
|
745 | |
update pod
|
746 |
他のメソッドと同様にC<execute()>においてもC<filter>を指定することができます。 |
747 | ||
748 |
$dbi->execute($sql, param => {title => 'Perl', author => '%Ken%'} |
|
749 |
filter => {title => 'to_something'); |
|
750 | ||
751 |
C<execute>のひとつの注意点としてはC<apply_filter()>で適用されたフィルタ |
|
752 |
はデフォルトでは有効ではないということに注意してください。 |
|
753 |
C<apply_filter()>で適用されたフィルタを有効にするには、 |
|
754 |
C<table>を指定する必要があります。 |
|
755 | ||
756 |
$dbi->execute($sql, param => {title => 'Perl', author => '%Ken%'} |
|
757 |
table => ['book']); |
|
758 | ||
759 |
=head2 タグ一覧 |
|
760 | ||
761 |
L<DBIx::Custom>では次のタグが使用可能です。 |
|
updated document
|
762 | |
763 |
このようにタグを使ってSQL文を表現するのがL<DBIx::Custom>の |
|
764 |
特徴です。以下のタグが利用可能です。 |
|
765 | ||
update pod
|
766 |
=head3 C<?> |
767 | ||
768 |
C<?>タグは以下のように展開されます。 |
|
769 | ||
770 |
{? NAME} -> ? |
|
771 | ||
772 |
=head3 C<=> |
|
773 | ||
774 |
C<=>タグは以下のように展開されます。 |
|
775 | ||
776 |
{= NAME} -> NAME = ? |
|
777 | ||
778 |
=head3 C<E<lt>E<gt>> |
|
779 | ||
780 |
C<E<lt>E<gt>>タグは以下のように展開されます。 |
|
781 | ||
782 |
{<> NAME} -> NAME <> ? |
|
783 | ||
784 |
=head3 C<E<lt>> |
|
785 | ||
786 |
C<E<lt>>タグは以下のように展開されます。 |
|
787 | ||
788 |
{< NAME} -> NAME < ? |
|
789 | ||
790 |
=head3 C<E<gt>> |
|
791 | ||
792 |
C<E<gt>>タグは以下のように展開されます。 |
|
793 | ||
794 |
{> NAME} -> NAME > ? |
|
795 | ||
796 |
=head3 C<E<gt>=> |
|
797 | ||
798 |
C<E<gt>=>タグは以下のように展開されます。 |
|
799 | ||
800 |
{>= NAME} -> NAME >= ? |
|
801 | ||
802 |
=head3 C<E<lt>=> |
|
803 | ||
804 |
C<E<lt>=>タグは以下のように展開されます。 |
|
805 | ||
806 |
{<= NAME} -> NAME <= ? |
|
807 | ||
808 |
=head3 C<like> |
|
809 | ||
810 |
C<like>タグは以下のように展開されます。 |
|
811 | ||
812 |
{like NAME} -> NAME like ? |
|
813 | ||
814 |
=head3 C<in> |
|
815 | ||
816 |
C<in>タグは以下のように展開されます。プレースホルダの |
|
817 |
数を引数で指定する必要があることに注意してください。 |
|
818 | ||
819 |
{in NAME COUNT} -> NAME in [?, ?, ..] |
|
820 | ||
821 |
=head3 C<insert_param> |
|
822 | ||
823 |
C<insert_param>タグは以下のように展開されます。 |
|
824 | ||
updated document
|
825 |
{insert_param NAME1 NAME2} -> (NAME1, NAME2) values (?, ?) |
update pod
|
826 | |
827 |
=head3 C<update_param> |
|
828 | ||
829 |
C<update_param>タグは以下のように展開されます。 |
|
830 | ||
updated document
|
831 |
{update_param NAME1 NAME2} -> set NAME1 = ?, NAME2 = ? |
832 | ||
update pod
|
833 |
=head2 同名の列の扱い |
updated document
|
834 | |
update pod
|
835 |
同名の列を含むタグがある場合にも、SQLを実行することができます。 |
836 |
たとえば、二つの日付で比較しなければならない場合を |
|
837 |
考えて見ましょう。 |
|
updated document
|
838 | |
update pod
|
839 |
my $sql = "select * from table where {> date} and {< date};"; |
updated document
|
840 | |
update pod
|
841 |
このような場合は対応するパラメータの値を配列のリファレンスにします。 |
removed experimental txn_sco...
|
842 | |
update pod
|
843 |
my $dbi->execute($sql, param => {date => ['2010-10-01', '2012-02-10']}); |
844 | ||
845 |
=head2 タグの追加 C<register_tag()> |
|
846 | ||
cleanup
|
847 |
L<DBIx::Custom>ではタグを独自に追加することができます。 |
update pod
|
848 |
タグを追加するにはC<register_tag()>を使用します。 |
removed experimental txn_sco...
|
849 | |
850 |
$dbi->register_tag( |
|
update pod
|
851 |
'=' => sub { |
852 |
my $column = shift; |
|
853 |
|
|
854 |
return ["$column = ?", [$column]]; |
|
removed experimental txn_sco...
|
855 |
} |
856 |
); |
|
857 | ||
update pod
|
858 |
ここではデフォルトのC<=>タグがどのように実装されているかを示しています。 |
859 |
タグを登録する関数の引数はタグの中に書かれた引数になります。 |
|
860 | ||
861 |
{タグ名 引数1 引数2} |
|
862 | ||
863 |
C<=>タグの場合は |
|
864 | ||
865 |
{= title} |
|
866 | ||
867 |
という形式ですから、サブルーチンにはtitleというひとつの列名がわたってきます。 |
|
868 | ||
869 |
サブルーチンの戻り値には次の形式の配列のリファレンスを返す必要があります。 |
|
870 | ||
871 |
[ |
|
872 |
展開後の文字列, |
|
873 |
[プレースホルダに埋め込みに利用する列名1, 列名2, ...] |
|
874 |
] |
|
875 | ||
876 |
一つ目の要素は展開後の文字列です。この例では |
|
877 | ||
878 |
'title = ?' |
|
879 | ||
880 |
を返す必要があります。 |
|
881 | ||
882 |
二つ目の要素はプレースホルダに埋め込みに利用する列名を含む配列の |
|
883 |
リファレンスです。今回の例では |
|
884 | ||
885 |
['title'] |
|
886 | ||
887 |
を返す必要があります。複数のプレースホルダを含む場合は、この部分が |
|
888 |
複数になります。C<insert_param>タグやC<update_param>タグは |
|
889 |
この部分が実際複数になっています。 |
|
890 | ||
891 |
上記を合わせると |
|
892 | ||
893 |
['title = ?', ['title']] |
|
894 |
|
|
895 |
を返す必要があるということです。 |
|
896 | ||
added experimental not_exist...
|
897 |
タグの実装の他のサンプルはL<DBIx::Custom::Tag>のソースコード |
898 |
をご覧になってみてください。 |
|
899 | ||
removed experimental txn_sco...
|
900 |
=head2 6. Where句の動的な生成 |
901 | ||
added experimental not_exist...
|
902 |
=head3 Where句の動的な生成 where() |
903 | ||
904 |
複数の検索条件を指定して、検索を行いたい場合があります。 |
|
905 |
次の3つのケースのwhere句を考えてみましょう。 |
|
906 |
下記のようなwhere句が必要になります。 |
|
907 | ||
908 |
titleの値だけで検索したい場合 |
|
909 | ||
910 |
where {= title} |
|
911 | ||
912 |
authorの値だけで検索したい場合 |
|
913 | ||
914 |
where {= author} |
|
915 | ||
916 |
titleとauthorの両方の値で検索したい場合 |
|
917 | ||
918 |
where {= title} and {=author} |
|
919 | ||
920 |
L<DBIx::Custom>では動的なWhere句の生成をサポートしています。 |
|
921 |
まずC<where()>でL<DBIx::Custom::Where>オブジェクトを生成します。 |
|
922 | ||
923 |
my $where = $dbi->where; |
|
924 | ||
925 |
次にC<clause()>を使用してwhere句を記述します。 |
|
926 | ||
927 |
$where->clause( |
|
928 |
['and', '{= title'}, '{= author}'] |
|
929 |
); |
|
930 | ||
931 |
clauseの指定方法は次のようになります。 |
|
932 | ||
933 |
['or' あるいは 'and', タグ1, タグ2, タグ3] |
|
934 | ||
935 |
第一引数にはorあるいはandを指定します。第二引数以降には |
|
936 |
検索条件をタグを使って記述します。 |
|
937 | ||
938 |
C<clause>の指定は入れ子にすることもでき、さらに複雑な条件 |
|
939 |
を記述することもできます。 |
|
940 | ||
941 |
['and', |
|
942 |
'{= title}', |
|
943 |
['or', '{= author}', '{like date}'] |
|
944 |
] |
|
945 | ||
946 |
このようにC<clause>を設定した後にC<param>にパラメータを指定します。 |
|
947 |
|
|
948 |
my $param => {title => 'Perl'}; |
|
949 |
$where->param($param); |
|
950 | ||
951 |
この例ではtitleだけがパラメータに含まれています。 |
|
952 | ||
953 |
この後C<to_string()>を実行すると$paramに含まれるパラメータを満たす |
|
954 |
where句を生成することができます。 |
|
955 | ||
956 |
my $where_clause = $where->to_string; |
|
957 | ||
958 |
パラメータはtitleだけですので、次のようなwhere句が生成されます。 |
|
959 | ||
960 |
where {= title} |
|
961 | ||
cleanup
|
962 |
またL<DBIx::Custom>は文字列の評価をオーバーロードして、C<to_string()> |
added experimental not_exist...
|
963 |
を呼び出すようにしていますので、次のようにしてwhere句を生成することも |
964 |
できます。 |
|
965 | ||
966 |
my $where_clause = "$where"; |
|
967 | ||
968 |
これはSQLの中にwhere句を埋め込むときにとても役立つ機能です。 |
|
969 | ||
make delete() using where ob...
|
970 |
=head3 同一の列名を含む場合 |
added experimental not_exist...
|
971 | |
make delete() using where ob...
|
972 |
タグの中に同一の名前を持つものが存在した場合でも動的に |
973 |
where句を作成することができます。 |
|
added experimental not_exist...
|
974 | |
make delete() using where ob...
|
975 |
たとえば、パラメータとして開始日付と終了日付を受け取ったことを |
976 |
考えてみてください。 |
|
added experimental not_exist...
|
977 | |
make delete() using where ob...
|
978 |
my $param = {start_date => '2010-11-15', end_date => '2011-11-21'}; |
added experimental not_exist...
|
979 | |
make delete() using where ob...
|
980 |
また開始日付と終了日付の片方だけや、どちらも受け取らない場合もあるかもしれません。 |
added experimental not_exist...
|
981 | |
make delete() using where ob...
|
982 |
この場合は次のようなパラメータに変換することで対応することができます。 |
added experimental not_exist...
|
983 | |
make delete() using where ob...
|
984 |
my $p = {date => ['2010-11-15', '2011-11-21']}; |
added experimental not_exist...
|
985 | |
make delete() using where ob...
|
986 |
値が配列のリファレンスになっていることに注目してください。このようにすれば |
987 |
同名の列を含むタグに順番に埋め込むことができます。 |
|
added experimental not_exist...
|
988 | |
make delete() using where ob...
|
989 |
$where->clause( |
990 |
['and', '{> date}', '{< date}'] |
|
991 |
); |
|
992 |
$where->param($p); |
|
993 | ||
994 |
また開始日付が存在しない場合は次のようなデータを作成します。 |
|
995 | ||
996 |
my $p = {date => [$dbi->not_exists, '2011-11-21']}; |
|
997 | ||
998 |
L<DBIx::Custom>のC<not_exists>でDBIx::Custom::NotExistsオブジェクトを |
|
999 |
取得できます。これは対応する値が存在しないことを示すためのものです。 |
|
1000 | ||
1001 |
また終了日付が存在しない場合は次のようなデータを作成します。 |
|
1002 | ||
1003 |
my $p = {date => ['2010-11-15']}; |
|
added experimental not_exist...
|
1004 | |
make delete() using where ob...
|
1005 |
どちらも存在しない場合は次のようなデータを作成します。 |
1006 | ||
1007 |
my $p = {date => []}; |
|
1008 | ||
1009 |
少し難しいので一番簡単に作成できるロジックを示しておきます。 |
|
1010 | ||
1011 |
my @date; |
|
1012 |
push @date, exists $param->{start_date} ? $param->{start_date} |
|
1013 |
: $dbi->not_exists; |
|
1014 |
push @date, $param->{end_date} if exists $param->{end_date}; |
|
1015 |
my $p = {date => \@date}; |
|
1016 | ||
1017 |
=head3 C<select()>との連携 |
|
1018 | ||
update pod
|
1019 |
L<DBIx::Custom::Where>オブジェクトは |
1020 |
C<select()>のC<where>に直接渡すことが |
|
make delete() using where ob...
|
1021 |
できます。 |
1022 |
|
|
1023 |
my $where = $dbi->where; |
|
1024 |
$where->clause(...); |
|
1025 |
$where->param($param); |
|
1026 |
my $result = $dbi->select(table => 'book', where => $where); |
|
1027 | ||
update pod
|
1028 |
あるいはC<update()>、C<delete()>のwhereに指定することも可能です。 |
make delete() using where ob...
|
1029 | |
1030 |
=head3 C<execute()>との連携 |
|
1031 | ||
1032 |
C<execute()>との連携です。SQLを作成するときに埋め込むことができます。 |
|
1033 | ||
1034 | ||
1035 |
my $where = $dbi->where; |
|
1036 |
$where->clause(...); |
|
1037 |
$where->param($param); |
|
1038 | ||
1039 |
my $sql = <<"EOS" |
|
1040 |
select * from book; |
|
1041 |
$where |
|
1042 |
EOS |
|
added experimental not_exist...
|
1043 | |
make delete() using where ob...
|
1044 |
$dbi->execute($sql, param => $param); |
added experimental not_exist...
|
1045 | |
update pod
|
1046 |
=head2 7. テーブルモデル |
1047 | ||
1048 |
=head3 テーブルオブジェクトの作成 C<table()> |
|
1049 | ||
1050 |
L<DBIx::Custom>はロジックとしてテーブルを中心にすえた |
|
1051 |
モデルの作成を支援します。 |
|
1052 | ||
1053 |
アプリケーションのロジックを記述するときに、そのロジックを |
|
1054 |
データベースのテーブルにすえることは、RDBMSを利用する |
|
1055 |
モデルであれば、コードの重複も少なく |
|
1056 |
わかりやすいものになります。 |
|
1057 | ||
1058 |
テーブルオブジェクトを生成するにはC<table()>を使用します。 |
|
1059 | ||
1060 |
my $table = $dbi->table('book'); |
|
1061 | ||
1062 |
実際にデータベースにテーブルは存在している必要はありません。 |
|
1063 |
これは仮想的なテーブルオブジェクトです。これは |
|
1064 |
L<DBIx::Customm::Table>オブジェクトになります。 |
|
1065 | ||
1066 |
テーブルオブジェクトからはC<insert()>、C<update()>、C<update_all()>、 |
|
1067 |
C<delete()>、C<delete_all()>、C<select()>などのメソッド呼び出すことができます。 |
|
1068 |
L<DBIx::Custom>と異なるところは、C<table>を必ずしも指定する必要が |
|
1069 |
ないということです。 |
|
1070 | ||
1071 |
$table->insert(param => $param); |
|
1072 | ||
1073 |
C<table>の値は自動的にbookに設定されます。 |
|
1074 | ||
1075 |
またテーブルオブジェクトには独自のメソッドを追加することができます。 |
|
1076 | ||
1077 |
$table->method( |
|
1078 |
register => sub { |
|
1079 |
my $self = shift; |
|
1080 |
my $table_name = $self->name; |
|
1081 |
# something |
|
1082 |
}, |
|
1083 |
list => sub { |
|
1084 |
my $self = shift; |
|
1085 |
my $table_name = $self->name; |
|
1086 |
# something |
|
1087 |
} |
|
1088 |
); |
|
1089 | ||
1090 |
メソッドに渡される第一引数はL<DBIx::Custom::Table>オブジェクトです。 |
|
1091 |
C<name()>を使用して、テーブル名を取得することができます。 |
|
1092 | ||
1093 |
このようにして登録したメソッドは直接呼び出すことができます。 |
|
1094 | ||
1095 |
$table->register(...); |
|
1096 |
$table->list(...); |
|
1097 | ||
1098 |
またテーブル専用のメソッドをオーバーライドして作成することもできます。 |
|
1099 | ||
1100 |
$table->method( |
|
1101 |
insert => sub { |
|
1102 |
my $self = shift; |
|
1103 |
|
|
1104 |
$self->base_insert(...); |
|
1105 |
|
|
1106 |
# something |
|
1107 |
} |
|
1108 |
); |
|
1109 | ||
1110 |
もともと存在していたC<insert()>を呼ぶにはC<base_$method>とします。L<DBIx::Custom::Table> |
|
1111 |
のオーバーライドの機能は簡易的なものですが、とても便利です。 |
|
1112 | ||
1113 |
=head2 テーブルで共有のメソッドの登録 |
|
1114 | ||
1115 |
すべてのテーブルでメソッドを共有するにはC<table>メソッドでテーブルを作成する前に、 |
|
1116 |
C<base_table>にメソッドを登録しておきます。 |
|
1117 | ||
1118 |
$dbi->base_table->method( |
|
1119 |
count => sub { |
|
1120 |
my $self = shift; |
|
1121 |
return $self->select(column => ['count(*)']); |
|
1122 |
} |
|
1123 |
); |
|
1124 | ||
1125 |
またテーブルからはL<DBIx::Custom>とL<DBI>のすべてのメソッドを呼び出すことができます。 |
|
1126 | ||
1127 |
# DBIx::Custom method |
|
1128 |
$table->execute($sql); |
|
1129 |
|
|
1130 |
# DBI method |
|
1131 |
$table->begin_work; |
|
1132 |
$table->commit; |
|
1133 | ||
1134 |
=head2 一般的なモデルの構成 |
|
1135 | ||
1136 |
一般的には、L<DBIx::Custom>を継承してコンストラクタの中に、モデルを作成 |
|
1137 |
するのがよいでしょう。 |
|
1138 | ||
1139 |
package MyDBI; |
|
1140 |
|
|
1141 |
use base 'DBIx::Custom'; |
|
1142 |
|
|
1143 |
sub connect { |
|
1144 |
my $self = shift->SUPER::connect(@_); |
|
1145 |
|
|
1146 |
$self->base_table->method( |
|
1147 |
... => sub { ... } |
|
1148 |
); |
|
1149 |
|
|
1150 |
$self->table('book')->method( |
|
1151 |
insert_multi => sub { ... }, |
|
1152 |
... => sub { ... } |
|
1153 |
); |
|
1154 |
|
|
1155 |
$self->table('company')->method( |
|
1156 |
... => sub { ... }, |
|
1157 |
); |
|
1158 |
} |
|
1159 | ||
1160 |
このようにして定義しておけば、次のように利用することができます。 |
|
1161 | ||
1162 |
my $dbi = MyDBI->connect(...); |
|
1163 |
$dbi->table('book')->insert_multi(...); |
|
1164 | ||
1165 |
=head2 8. パフォーマンスの改善 |
|
updated document
|
1166 | |
update pod
|
1167 |
=head3 クエリの作成 |
updated document
|
1168 | |
1169 |
もしC<insert()>メソッドを使用してインサートを実行した場合、 |
|
1170 |
必要なパフォーマンスを得られない場合があるかもしれません。 |
|
1171 |
C<insert()>メソッドは、SQL文とステートメントハンドルを |
|
update pod
|
1172 |
毎回作成するためです。 |
1173 | ||
1174 |
そのような場合は、C<query>オプションを指定することで、 |
|
1175 |
クエリを取得することができます。 |
|
1176 | ||
1177 |
my $query = $dbi->insert(table => 'book', param => $param, query => 1); |
|
1178 | ||
1179 |
またC<create_query()>メソッドを使って任意のSQLのクエリを作成 |
|
1180 |
することもできます。 |
|
updated document
|
1181 | |
1182 |
my $query = $dbi->create_query( |
|
update pod
|
1183 |
"insert into book {insert_param title author};"; |
updated document
|
1184 |
); |
1185 | ||
1186 |
戻り値はL<DBIx::Custom::Query>オブジェクトです。 |
|
1187 |
このオブジェクトはSQL文とパラメータバインド時の列名を |
|
1188 |
保持しています。またステートメントハンドルも保持しています。 |
|
1189 | ||
1190 |
{ |
|
1191 |
sql => 'insert into book (title, author) values (?, ?);', |
|
1192 |
columns => ['title', 'author'], |
|
1193 |
sth => $sth |
|
1194 |
} |
|
1195 | ||
update pod
|
1196 |
クエリオブジェクトを使って繰り返し実行するにはC<execute()>を使用します。 |
updated document
|
1197 |
|
update pod
|
1198 |
my $params = [ |
updated document
|
1199 |
{title => 'Perl', author => 'Ken'}, |
1200 |
{title => 'Good days', author => 'Mike'} |
|
1201 |
]; |
|
1202 |
|
|
update pod
|
1203 |
foreach my $param (@$paramss) { |
1204 |
$dbi->execute($query, table => 'book', param => $input); |
|
updated document
|
1205 |
} |
1206 | ||
1207 |
C<execute>メソッドの第一引数にクエリオブジェトを渡すことができます。 |
|
update pod
|
1208 |
C<insert()>メソッドよりも高速です。 |
updated document
|
1209 | |
update pod
|
1210 |
注意点がいくつかあります。それはパラメータの数は必ず同じでなくてはならない |
1211 |
ということです。最初に3つのパラメータだけを渡したのに、次の実行では |
|
1212 |
二つのパラメータを渡すと予期しない結果になります。それは |
|
1213 |
動的に生成されたSQLに含まれるプレースホルダの数が異なるからです。 |
|
1214 |
またC<execute()>によっては自動的にはフィルタが有効にならないので、 |
|
1215 |
C<table>を指定する必要のあることに注意してください。 |
|
1216 |
本当に必要な場合だけ利用してください。 |
|
updated document
|
1217 | |
update pod
|
1218 |
=head2 9. その他の機能 |
updated document
|
1219 | |
update pod
|
1220 |
=head3 メソッドの登録 |
updated document
|
1221 | |
update pod
|
1222 |
メソッドを登録するにはC<method()>を使用します。 |
updated document
|
1223 | |
update pod
|
1224 |
$dbi->method( |
updated document
|
1225 |
update_or_insert => sub { |
1226 |
my $self = shift; |
|
update pod
|
1227 |
# something |
updated document
|
1228 |
}, |
1229 |
find_or_create => sub { |
|
1230 |
my $self = shift; |
|
update pod
|
1231 |
# something |
updated document
|
1232 |
} |
1233 |
); |
|
1234 | ||
update pod
|
1235 |
<method()>で登録したメソッドは |
updated document
|
1236 |
L<DBIx::Custom>オブジェクトから直接呼び出すことができます。 |
1237 | ||
1238 |
$dbi->update_or_insert; |
|
1239 |
$dbi->find_or_create; |
|
1240 | ||
removed experimental expand
|
1241 |
=head3 結果クラスの変更 |
1242 | ||
1243 |
必要ならば結果クラスを変更することができます。 |
|
1244 | ||
1245 |
package MyResult; |
|
1246 |
use base 'DBIx::Custom::Result'; |
|
1247 |
|
|
1248 |
sub some_method { ... } |
|
updated document
|
1249 | |
removed experimental expand
|
1250 |
1; |
1251 |
|
|
1252 |
package main; |
|
1253 |
|
|
1254 |
use MyResult; |
|
1255 |
|
|
1256 |
my $dbi = DBIx::Custom->connect(...); |
|
1257 |
$dbi->result_class('MyResult'); |
|
updated document
|
1258 | |
removed experimental expand
|
1259 |
=head3 キャッシング |
updated document
|
1260 | |
removed experimental expand
|
1261 |
タグの展開後のSQLはパフォーマンスの理由のためにキャッシュされます。 |
1262 |
これはC<chace>で設定でき、デフォルトではキャッシュを行う設定です。 |
|
updated document
|
1263 | |
removed experimental expand
|
1264 |
$dbi->cache(1); |
updated document
|
1265 | |
removed experimental expand
|
1266 |
キャッシュ方法はC<cache_method>にメソッドを指定することで |
1267 |
変更することができます。 |
|
1268 |
データの保存と取得のためのメソッドを定義します。 |
|
updated document
|
1269 | |
removed experimental expand
|
1270 |
デフォルトでは次のようにメモリ上にキャッシュを行うものになっています。 |
updated document
|
1271 | |
removed experimental expand
|
1272 |
$dbi->cache_method(sub { |
1273 |
sub { |
|
1274 |
my $self = shift; |
|
1275 |
|
|
1276 |
$self->{_cached} ||= {}; |
|
1277 |
|
|
1278 |
if (@_ > 1) { |
|
1279 |
# Set |
|
1280 |
$self->{_cached}{$_[0]} = $_[1] |
|
1281 |
} |
|
1282 |
else { |
|
1283 |
# Get |
|
1284 |
return $self->{_cached}{$_[0]} |
|
1285 |
} |
|
1286 |
} |
|
1287 |
}); |
|
1288 |
|
|
1289 |
第一はL<DBIx::Custom>オブジェクトです。 |
|
1290 |
第二引数はタグの展開される前のSQLです。 |
|
1291 |
第三引数はタグの展開後のSQLです。 |
|
updated document
|
1292 | |
removed experimental expand
|
1293 |
自分で作成する場合は第三引数が存在した場合はキャッシュを設定し、 |
1294 |
存在しなかった場合はキャッシュを取得する実装に |
|
1295 |
してください。 |
|
updated document
|
1296 | |
1297 |
=cut |