added experimental expand me...
|
1 |
=encoding utf8 |
2 | ||
updated document
|
3 |
=head1 NAME |
added experimental expand me...
|
4 | |
pod fix
|
5 |
DBIx::Custom::Guide::Ja - DBIx::Customの日本語ガイド |
added experimental expand me...
|
6 | |
7 |
=head1 ガイド |
|
8 | ||
9 |
L<DBIx::Custom>はデータベースへのクエリの発行を簡単に行うための |
|
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 | |
26 |
L<DBIx::Custom>の仕組みを簡単に説明しておきましょう。 |
|
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 |
これらの展開にはどのような意味があるのでしょうかと質問 |
|
updated document
|
38 |
されることかと思います。この簡単な仕組みの上に非常にたくさんの |
39 |
有用で便利で使いやすい機能が構築されます。それは以下のようなものです。 |
|
updated document
|
40 | |
updated document
|
41 |
=over 4 |
updated document
|
42 | |
updated document
|
43 |
=item 1. プレースホルダのパラメータをハッシュリファレンスで指定 |
updated document
|
44 | |
updated document
|
45 |
L<DBI>をそのまま使うのであればプレースホルダのパラメータは配列 |
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 | ||
56 |
=item 2. パラメータのフィルタリング |
|
57 | ||
58 |
たとえば、日付の列は、Perlで扱うときにはC<Time::Piece>などの日付オブジェクト |
|
59 |
で扱い、データベースに格納するときはデータベースの日付型に変換したい |
|
60 |
と思うのではないでしょうか。またデータベースから取り出すときは |
|
61 |
データベースの日付型から日付オブジェクトに変換したと思うのでは |
|
62 |
ないでしょうか。 |
|
63 | ||
64 |
このようなときはフィルタ機能を使うことができます。 |
|
65 | ||
66 |
まずフィルタを登録します。 |
|
67 | ||
68 |
$dbi->register_filter( |
|
69 |
tp_to_date => sub { |
|
70 |
... |
|
71 |
}, |
|
72 |
date_to_tp => sub { |
|
73 |
... |
|
74 |
} |
|
75 |
); |
|
76 | ||
77 |
次にテーブルの各列にこのフィルタを適用します。 |
|
78 | ||
79 |
$dbi->apply_filter('book', |
|
80 |
'publish_date' => {out => 'tp_to_date', in => 'date_to_tp'} |
|
81 |
); |
|
82 | ||
83 |
outはPerlからデータベースに保存する方向、inはデータベースからPerlに取得する方向です。 |
|
84 | ||
85 |
SQLを発行するときにテーブルの指定を行えば、自動的にこのフィルタが適用されます。 |
|
86 | ||
87 |
$dbi->execute($sql, $param, table => 'book'); |
|
88 | ||
89 |
=item 3. 選択的な検索条件 |
|
90 | ||
91 |
生のDBIを利用しているとき一番たいへんなのは選択的な検索条件を作成したいときです。 |
|
92 | ||
93 |
たとえば、検索条件にtitleとauthorが指定された場合は次のSQLを |
|
94 | ||
95 |
select * from book where title = ? and author = ?; |
|
96 | ||
97 |
titleだけの場合は次のSQLを |
|
98 | ||
99 |
select * from book where title = ?; |
|
100 |
|
|
101 |
authorだけの場合は次のSQLを発行した場合を考えましょう。 |
|
102 | ||
103 |
select * from book where author = ?; |
|
104 | ||
105 |
これはとても大変な作業なので、通常はL<SQL::Abstract>を動的に生成してくれる |
|
106 |
モジュールを利用することになります。 |
|
107 | ||
108 |
L<DBIx::Custom>はさらに簡単で便利な方法を用意しています。 |
|
109 | ||
110 |
my $where = $dbi->where; |
|
111 |
$where->param({title => 'Perl'}); |
|
112 |
$where->clause( |
|
113 |
['and', '{= title}', {'= author'}] |
|
114 |
); |
|
115 | ||
116 |
my $sql = "select * from book $where"; |
|
117 | ||
118 |
詳しい説明は後ほど行いますが、上記のように記述すれば、 |
|
119 |
L<DBIx::Custom>では選択的な検索条件を持つWhere句を生成することができます。 |
|
120 |
検索条件が入れ子になった構造やorについても対応しています。 |
|
121 | ||
122 |
=item 4. 挿入、更新、削除、選択を行うためのメソッド |
|
123 | ||
124 |
L<DBIx::Custom>ではSQLをさらに簡単に実行するための |
|
125 |
メソッドも提供しています。 |
|
added experimental expand me...
|
126 |
C<insert()>, C<update()>, C<delete()>,C<select()>などの |
updated document
|
127 |
シュガーメソッドを使って、挿入、更新、削除、選択という操作を行うことが |
128 |
できます。 |
|
129 | ||
130 |
my $param = {title => 'Perl', author => 'Ken'}; |
|
131 |
$dbi->insert(table => 'book', param => $param); |
|
132 | ||
133 |
=item 5. テーブル単位の操作の登録 |
|
134 | ||
135 |
テーブルに対して操作を登録することができます。これによって |
|
136 |
テーブル名を繰り返し指定する必要がなくなり、ソースコードの |
|
137 |
見通しが良くなります。 |
|
138 | ||
139 |
$dbi->talbe('book', |
|
140 |
list => sub { |
|
141 |
... |
|
142 |
}, |
|
143 |
list_somethin => sub { |
|
144 |
|
|
145 |
} |
|
146 |
); |
|
147 | ||
148 |
登録したメソッドはそのまま利用することができます。 |
|
149 | ||
150 |
$dbi->table('book')->list; |
|
added experimental expand me...
|
151 | |
updated document
|
152 |
通常O/Rマッパはテーブルに対応するクラスを作成しなければ |
153 |
ならないことが多いですが、L<DBIx::Custom>ではこの作業を簡便に |
|
154 |
しており、上記のように登録することができます。 |
|
added experimental expand me...
|
155 | |
updated document
|
156 |
=back |
157 | ||
158 |
L<DBIx::Custom>はL<DBI>を補うとても便利なモジュールです。 |
|
159 |
興味をもたれた方は、この後で詳しい解説を行いますので、 |
|
160 |
ご覧になってみてください。 |
|
added experimental expand me...
|
161 | |
162 |
=head2 1. データベースへの接続 |
|
163 | ||
164 |
L<DBIx::Custom>オブジェクトを生成し、データベースに接続するには |
|
165 |
C<connect()>メソッドを使用します。 |
|
166 | ||
167 |
use DBIx::Custom; |
|
168 |
my $dbi = DBIx::Custom->connect(data_source => "dbi:mysql:database=dbname", |
|
169 |
user => 'ken', password => '!LFKD%$&'); |
|
170 | ||
deprecated DBIx::Custom::MyS...
|
171 |
B<Data sourceのサンプル:> |
added experimental expand me...
|
172 | |
deprecated DBIx::Custom::MyS...
|
173 |
MySQL |
added experimental expand me...
|
174 | |
deprecated DBIx::Custom::MyS...
|
175 |
"dbi:mysql:database=$database" |
176 |
"dbi:mysql:database=$database;host=$hostname;port=$port" |
|
added experimental expand me...
|
177 | |
deprecated DBIx::Custom::MyS...
|
178 |
SQLite |
179 | ||
180 |
"dbi:SQLite:dbname=$database" |
|
181 |
"dbi:SQLite:dbname=:memory:" |
|
182 | ||
183 |
PostgreSQL |
|
184 | ||
185 |
"dbi:Pg:dbname=$dbname" |
|
186 | ||
187 |
Oracle |
|
188 | ||
189 |
"dbi:Oracle:$dbname" |
|
190 |
"dbi:Oracle:host=$host;sid=$sid" |
|
191 | ||
192 |
ODBC(Microsoft Access) |
|
193 | ||
194 |
"dbi:ODBC:driver=Microsoft Access Driver (*.mdb);dbq=hoge.mdb" |
|
195 | ||
196 |
ODBC(SQL Server) |
|
197 | ||
198 |
"dbi:ODBC:driver={SQL Server};Server=(local);database=test;Trusted_Connection=yes;AutoTranslate=No;" |
|
added experimental expand me...
|
199 | |
200 |
L<DBIx::Custom>はL<DBI>のラッパです。 |
|
201 |
L<DBI>オブジェクトはC<dbh>で取得することができます。 |
|
202 | ||
203 |
my $dbh = $dbi->dbh; |
|
204 | ||
205 |
データベースハンドル属性にはデフォルトで次のものが設定されます。 |
|
206 |
|
|
207 |
$dbi->dbh->{RaiseError} = 1; |
|
208 |
$dbi->dbh->{PrintError} = 0; |
|
209 |
$dbi->dbh->{AutoCommit} = 1; |
|
210 | ||
211 |
この設定を行っているので、致命的なエラーが起こると、 |
|
212 |
例外が発生しプログラムは終了します。 |
|
213 |
またクエリが発行されると自動的にコミットされます。 |
|
214 | ||
215 |
=head2 2. シュガーメソッド |
|
216 | ||
217 |
L<DBIx::Custom>は、 |
|
218 |
C<insert()>、C<update()>、C<delete()>、C<select()> |
|
219 |
のようなシュガーメソッドを持っています。 |
|
220 |
小さなことを行うのであれば、SQL文を |
|
221 |
作成する必要はありません。 |
|
222 | ||
223 |
=head3 C<insert()> |
|
224 | ||
225 |
C<insert>メソッドです。データベースにデータを挿入します。 |
|
226 | ||
remove DBIx::Custom::Model
|
227 |
$dbi->insert(table => 'book', |
added experimental expand me...
|
228 |
param => {title => 'Perl', author => 'Ken'}); |
229 | ||
230 |
これは次のL<DBI>の操作と同じです。 |
|
231 | ||
232 |
my $sth = $dbh->prepare('insert into (title, author) values (?, ?);'); |
|
233 |
$sth->execute('Perl', 'Ken'); |
|
234 | ||
235 |
=head3 C<update()> |
|
236 | ||
237 |
C<update>メソッドです。データベースのデータを更新します。 |
|
238 | ||
remove DBIx::Custom::Model
|
239 |
$dbi->update(table => 'book', |
added experimental expand me...
|
240 |
param => {title => 'Perl', author => 'Ken'}, |
241 |
where => {id => 5}); |
|
242 | ||
243 |
これは次のL<DBI>の操作と同じです。 |
|
244 | ||
245 |
my $sth = $dbh->prepare( |
|
remove DBIx::Custom::Model
|
246 |
'update book set title = ?, author = ? where id = ?;'); |
added experimental expand me...
|
247 |
$sth->execute('Perl', 'Ken', 5); |
248 | ||
249 |
C<update>メソッドは安全のため |
|
250 |
where句のないSQLを発行することを許可していません。 |
|
251 |
もしすべての行を更新したい場合は |
|
252 |
C<update_all()>メソッドを使用してください。 |
|
253 | ||
remove DBIx::Custom::Model
|
254 |
$dbi->update_all(table => 'book', |
added experimental expand me...
|
255 |
param => {title => 'Perl', author => 'Ken'}); |
256 | ||
257 |
=head3 C<delete()> |
|
258 | ||
259 |
C<delete>メソッドです。データベースのデータを削除します。 |
|
260 | ||
remove DBIx::Custom::Model
|
261 |
$dbi->delete(table => 'book', |
added experimental expand me...
|
262 |
where => {author => 'Ken'}); |
263 | ||
264 |
これは次のL<DBI>の操作と同じです。 |
|
265 | ||
remove DBIx::Custom::Model
|
266 |
my $sth = $dbh->prepare('delete from book where id = ?;'); |
added experimental expand me...
|
267 |
$sth->execute('Ken'); |
268 | ||
269 |
C<delete>メソッドは安全のため |
|
270 |
where句のないSQLを発行することを許可していません。 |
|
271 |
もしすべての行を削除したい場合は |
|
272 |
C<delete_all()>メソッドを使用してください。 |
|
273 | ||
remove DBIx::Custom::Model
|
274 |
$dbi->delete_all(table => 'book'); |
added experimental expand me...
|
275 | |
276 |
=head3 C<select()> |
|
277 | ||
278 |
C<select>メソッドです。テーブル名だけを指定しています。 |
|
279 | ||
remove DBIx::Custom::Model
|
280 |
my $result = $dbi->select(table => 'book'); |
added experimental expand me...
|
281 | |
282 |
これは次のL<DBI>の操作と同じです。 |
|
283 | ||
remove DBIx::Custom::Model
|
284 |
my $sth = $dbh->prepare('select * from book;); |
added experimental expand me...
|
285 |
$sth->execute; |
286 | ||
287 |
C<select()>メソッドの戻り値はL<DBIx::Custom::Result> |
|
288 |
オブジェクトです。C<fetch>メソッドを使用して |
|
289 |
行をフェッチすることができます。 |
|
290 | ||
291 |
while (my $row = $result->fetch) { |
|
292 |
my $title = $row->[0]; |
|
293 |
my $author = $row->[1]; |
|
294 |
} |
|
295 | ||
296 |
次のC<select>は行の名前とwhere句を指定したものです。 |
|
297 | ||
298 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
299 |
table => 'book', |
added experimental expand me...
|
300 |
column => [qw/author title/], |
301 |
where => {author => 'Ken'} |
|
302 |
); |
|
303 | ||
304 |
次のL<DBI>の操作と同じです。 |
|
305 |
|
|
306 |
my $sth = $dbh->prepare( |
|
remove DBIx::Custom::Model
|
307 |
'select author, title from book where author = ?;'); |
added experimental expand me...
|
308 |
$sht->execute('Ken'); |
309 | ||
310 |
テーブルをjoinしたい場合はC<relation>を使用します。 |
|
311 | ||
312 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
313 |
table => ['book', 'rental'], |
314 |
column => ['book.name as book_name'] |
|
315 |
relation => {'book.id' => 'rental.book_id'} |
|
added experimental expand me...
|
316 |
); |
317 | ||
318 |
次のL<DBI>の操作と同じです。 |
|
319 | ||
320 |
my $sth = $dbh->prepare( |
|
remove DBIx::Custom::Model
|
321 |
'select book.name as book_name from book, rental' . |
322 |
'where book.id = rental.book_id;'); |
|
added experimental expand me...
|
323 |
$sth->execute; |
324 | ||
325 |
SQL文の末尾に文字列を追加したい場合は<append>オプションを使用します。 |
|
326 | ||
327 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
328 |
table => 'book', |
added experimental expand me...
|
329 |
where => {author => 'Ken'}, |
330 |
append => 'order by price limit 5', |
|
331 |
); |
|
332 | ||
333 |
次のL<DBI>の操作と同じです。 |
|
334 | ||
335 |
my $sth = $dbh->prepare( |
|
remove DBIx::Custom::Model
|
336 |
'select * book where author = ? order by price limit 5;'); |
added experimental expand me...
|
337 |
$sth->execute; |
338 | ||
339 |
C<append>オプションは、C<insert()>、C<update()>、C<update_all()> |
|
340 |
C<delete()>、C<select>メソッドで使用することが |
|
341 |
できます。 |
|
342 | ||
343 |
この後のフィルタリングの解説で詳しく扱いますが、値をフィルタリングしたい |
|
344 |
場合はC<filter>オプションを使用することができます。 |
|
345 | ||
remove DBIx::Custom::Model
|
346 |
$dbi->insert(table => 'book', |
added experimental expand me...
|
347 |
param => {title => 'Perl', author => 'Ken'}); |
348 |
filter => {title => 'encode_utf8', |
|
updated document
|
349 |
author => 'encode_utf8'}); |
350 | ||
351 |
C<filter>オプションは、C<insert()>、C<update()>、C<update_all()> |
|
352 |
C<delete()>、C<select>メソッドで使用することが |
|
353 |
できます。 |
|
354 | ||
355 |
C<select()>メソッドのC<where>オプションではハッシュの代わりに |
|
356 |
タグを利用することもできます。これによって柔軟な |
|
357 |
条件を指定することができます。 |
|
358 | ||
359 |
# Select, more flexible where |
|
360 |
my $result = $dbi->select( |
|
361 |
table => 'book', |
|
362 |
where => ['{= author} and {like title}', |
|
363 |
{author => 'Ken', title => '%Perl%'}] |
|
364 |
); |
|
365 | ||
366 |
タグについては以降で解説します。 |
|
367 | ||
368 |
=head2 3. 行のフェッチ |
|
369 | ||
370 |
C<select()>メソッドの戻り値であるL<DBIx::Custom::Result> |
|
371 |
には行をフェッチするためのさまざまなメソッドが |
|
372 |
用意されています。 |
|
373 |
(このセクションの解説では「配列」は「配列のリファレンス」を |
|
374 |
「ハッシュ」は「ハッシュのリファレンス」を意味しますので |
|
375 |
注意してください。) |
|
376 | ||
377 |
=head3 C<fetch> |
|
378 | ||
379 |
一行フェッチして配列に格納します。 |
|
380 | ||
381 |
while (my $row = $result->fetch) { |
|
382 |
my $author = $row->[0]; |
|
383 |
my $title = $row->[1]; |
|
384 |
} |
|
385 | ||
386 |
=head3 C<fetch_first> |
|
387 | ||
388 |
一行だけフェッチして配列に格納します。 |
|
389 | ||
390 |
my $row = $result->fetch_first; |
|
391 | ||
392 |
フェッチが終わった後は、ステートメントハンドルからC<finish()> |
|
393 |
メソッドが呼び出されてそれ以上フェッチできなくなります。 |
|
394 | ||
395 |
=head3 C<fetch_multi> |
|
396 | ||
397 |
複数行をフェッチして配列の配列に格納します。 |
|
398 | ||
399 |
while (my $rows = $result->fetch_multi(5)) { |
|
400 |
my $first_author = $rows->[0][0]; |
|
401 |
my $first_title = $rows->[0][1]; |
|
402 |
my $second_author = $rows->[1][0]; |
|
403 |
my $second_value = $rows->[1][1]; |
|
404 |
} |
|
405 | ||
406 |
=head3 C<fetch_all> |
|
407 | ||
408 |
すべての行をフェッチして配列の配列に格納します。 |
|
409 | ||
410 |
my $rows = $result->fetch_all; |
|
411 | ||
412 |
=head3 C<fetch_hash> |
|
413 | ||
414 |
一行フェッチしてハッシュに格納します。 |
|
415 | ||
416 |
while (my $row = $result->fetch_hash) { |
|
417 |
my $title = $row->{title}; |
|
418 |
my $author = $row->{author}; |
|
419 |
} |
|
420 | ||
421 |
=head3 C<fetch_hash_first> |
|
422 | ||
423 |
一行だけフェッチしてハッシュに格納します。 |
|
424 | ||
425 |
my $row = $result->fetch_hash_first; |
|
426 | ||
427 |
フェッチが終わった後は、ステートメントハンドルからC<finish()> |
|
428 |
メソッドが呼び出されてそれ以上フェッチできなくなります。 |
|
429 | ||
430 |
=head3 C<fetch_hash_multi> |
|
431 | ||
432 |
複数行をフェッチしてハッシュの配列に格納します。 |
|
433 | ||
434 |
while (my $rows = $result->fetch_hash_multi(5)) { |
|
435 |
my $first_title = $rows->[0]{title}; |
|
436 |
my $first_author = $rows->[0]{author}; |
|
437 |
my $second_title = $rows->[1]{title}; |
|
438 |
my $second_author = $rows->[1]{author}; |
|
439 |
} |
|
440 | ||
441 |
=head3 C<fetch_all> |
|
442 | ||
443 |
すべての行をフェッチしてハッシュの配列に格納します。 |
|
444 | ||
445 |
my $rows = $result->fetch_hash_all; |
|
446 | ||
447 |
L<DBI>のステートメントハンドルに直接アクセスしたい場合は |
|
448 |
<sth>を使用します。 |
|
449 | ||
450 |
my $sth = $result->sth; |
|
451 | ||
452 |
=head2 4. ハッシュパラメタバインド |
|
453 | ||
454 |
L<DBIx::Custom>はハッシュパラメタバインドを提供します。 |
|
455 | ||
456 |
まず最初にL<DBI>による通常のパラメタバインドをご覧ください。 |
|
457 | ||
458 |
use DBI; |
|
459 |
my $dbh = DBI->connect(...); |
|
460 |
my $sth = $dbh->prepare( |
|
461 |
"select * from book where author = ? and title like ?;" |
|
462 |
); |
|
463 |
$sth->execute('Ken', '%Perl%'); |
|
464 | ||
465 |
これはデータベースシステムがSQLをキャッシュすることができ、 |
|
466 |
パラメータは自動的にクォートされるので、 |
|
467 |
パフォーマンス面でも、セキュリティ面でも |
|
468 |
とても良い方法です。 |
|
469 | ||
470 | ||
471 |
L<DBIx::Custom>はこれを改善して、ハッシュで |
|
472 |
パラメタを指定できるようにしました。 |
|
473 | ||
474 |
my $result = $dbi->execute( |
|
475 |
"select * from book where {= author} and {like title};" |
|
476 |
param => {author => 'Ken', title => '%Perl%'} |
|
477 |
); |
|
478 | ||
479 |
C<{= author}>とC<{like title}>はタグと呼ばれます。 |
|
480 |
タグは内部ではプレースホルダを含む文字列に置き換えられます。 |
|
481 | ||
482 |
select * from book where {= author} and {like title} |
|
483 | ||
484 |
という文は以下のSQLに置き換えられます。 |
|
485 | ||
486 |
select * from book where author = ? and title like ?; |
|
487 | ||
488 |
このようにタグを使ってSQL文を表現するのがL<DBIx::Custom>の |
|
489 |
特徴です。以下のタグが利用可能です。 |
|
490 | ||
491 |
[TAG] [REPLACED] |
|
492 |
{? NAME} -> ? |
|
493 |
{= NAME} -> NAME = ? |
|
494 |
{<> NAME} -> NAME <> ? |
|
495 |
|
|
496 |
{< NAME} -> NAME < ? |
|
497 |
{> NAME} -> NAME > ? |
|
498 |
{>= NAME} -> NAME >= ? |
|
499 |
{<= NAME} -> NAME <= ? |
|
500 |
|
|
501 |
{like NAME} -> NAME like ? |
|
502 |
{in NAME COUNT} -> NAME in [?, ?, ..] |
|
503 |
|
|
504 |
{insert_param NAME1 NAME2} -> (NAME1, NAME2) values (?, ?) |
|
505 |
{update_param NAME1 NAME2} -> set NAME1 = ?, NAME2 = ? |
|
506 | ||
507 |
これらの変換はL<DBIx::Custom::QueryBuilder>によって行われます。 |
|
508 | ||
509 |
C<{>とC<}>は予約語です。これらの文字を使いたい場合は |
|
510 |
「\」を使ってエスケープする必要があります。 |
|
511 |
'\'はPerlのエスケープ文字なので、 |
|
512 |
エスケープするためには'\\'と書く必要があることに注意 |
|
513 |
してください。 |
|
514 | ||
515 |
'select * from book \\{ something statement \\}' |
|
516 | ||
517 |
=head2 5. フィルタリング |
|
518 | ||
519 |
=head3 パラメタバインド時のフィルタリング |
|
520 | ||
521 |
データベースに登録するデータをフィルタリングしたい場合 |
|
522 |
があります。たとえば、内部文字列で文字列を保持している場合は |
|
523 |
データベースにデータを登録する前に、バイト文字列に変換する |
|
524 |
必要があります。L<DBIx::Custom>のフィルタリングシステムは |
|
525 |
あるデータを他のデータに変換するのを手助けしてくれます。 |
|
526 | ||
527 |
フィルタリングを利用するにはまず、 |
|
528 |
C<register_filter()>メソッドを使用して |
|
529 |
フィルタを登録しておく必要があります。 |
|
530 | ||
531 |
$dbi->register_filter( |
|
532 |
to_upper_case => sub { |
|
533 |
my $value = shift; |
|
534 |
return uc $value; |
|
535 |
} |
|
536 |
); |
|
537 | ||
538 |
デフォルトのフィルタとしてC<encode_utf8>とC<decode_utf8> |
|
539 |
が登録されています。 |
|
540 | ||
541 |
登録されているフィルタはC<execute()>メソッドのC<filter>オプション |
|
542 |
で指定することができます。 |
|
543 | ||
544 |
my $result = $dbi->execute( |
|
545 |
"select * from book where {= author} and {like title};" |
|
546 |
param => {author => 'Ken', title => '%Perl%'}, |
|
547 |
filter => {author => 'to_upper_case, title => 'encode_utf8'} |
|
548 |
); |
|
549 | ||
550 |
この例ではC<author>の値はバインドされるときに大文字に変換され、 |
|
551 |
C<title>の値はバイト文字列に変換されます。 |
|
552 | ||
553 |
C<filter>オプションは |
|
554 |
C<insert()>、C<update()>、 C<update_all()>, |
|
555 |
C<delete()>、C<select()> |
|
556 |
メソッドにおいても使用することができます。 |
|
557 | ||
558 |
# insert() with filter option |
|
559 |
$dbi->insert(table => 'book', |
|
560 |
param => {title => 'Perl', author => 'Ken'}, |
|
561 |
filter => {title => 'encode_utf8'}); |
|
562 |
|
|
563 |
# select() with filter option |
|
564 |
my $result = $dbi->select( |
|
565 |
table => 'book', |
|
566 |
column => [qw/author title/], |
|
567 |
where => {author => 'Ken'}, |
|
568 |
append => 'order by id limit 1', |
|
569 |
filter => {title => 'encode_utf8'} |
|
570 |
); |
|
571 | ||
572 |
B<フィルタのサンプル> |
|
573 | ||
574 |
MySQL |
|
575 | ||
576 |
# Time::Piece object to DATETIME format |
|
577 |
tp_to_datetime => sub { |
|
578 |
return shift->strftime('%Y-%m-%d %H:%M:%S'); |
|
579 |
} |
|
580 |
|
|
581 |
# Time::Piece object to DATE format |
|
582 |
tp_to_date => sub { |
|
583 |
return shift->strftime('%Y-%m-%d'); |
|
584 |
} |
|
585 |
|
|
586 |
# DATETIME to Time::Piece object |
|
587 |
datetime_to_tp => sub { |
|
588 |
return Time::Piece->strptime(shift, '%Y-%m-%d %H:%M:%S'); |
|
589 |
} |
|
590 |
|
|
591 |
# DATE to Time::Piece object |
|
592 |
date_to_tp => sub { |
|
593 |
return Time::Piece->strptime(shift, '%Y-%m-%d'); |
|
594 |
} |
|
595 | ||
596 |
SQLite |
|
597 |
|
|
598 |
# Time::Piece object to DATETIME format |
|
599 |
tp_to_datetime => sub { |
|
600 |
return shift->strftime('%Y-%m-%d %H:%M:%S'); |
|
601 |
} |
|
602 |
|
|
603 |
# Time::Piece object to DATE format |
|
604 |
tp_to_date => sub { |
|
605 |
return shift->strftime('%Y-%m-%d'); |
|
606 |
} |
|
607 |
|
|
608 |
# DATETIME to Time::Piece object |
|
609 |
datetime_to_tp => sub { |
|
610 |
return Time::Piece->strptime(shift, '%Y-%m-%d %H:%M:%S'); |
|
611 |
} |
|
612 |
|
|
613 |
# DATE to Time::Piece object |
|
614 |
date_to_tp => sub { |
|
615 |
return Time::Piece->strptime(shift, '%Y-%m-%d'); |
|
616 |
} |
|
617 | ||
618 |
=head3 行のフェッチ時のフィルタリング |
|
619 | ||
620 |
行をフェッチするときのフィルタも設定することができます。 |
|
621 |
これはL<DBIx::Custom::Result>クラスのC<filter>メソッドを使って |
|
622 |
行います。 |
|
623 | ||
624 |
my $result = $dbi->select(table => 'book'); |
|
625 |
$result->filter({title => 'decode_utf8', author => 'to_upper_case'}); |
|
626 | ||
627 |
フェッチのためのフィルタにおいて、 |
|
628 |
たとえ、列名が大文字を含む場合であっても |
|
629 |
列名は小文字であることに注意してください。 |
|
630 |
これはデータベースシステムに依存させないための要件です。 |
|
631 | ||
632 |
=head2 6. パフォーマンスの改善 |
|
633 | ||
634 |
=head3 シュガーメソッドを使わない |
|
635 | ||
636 |
もしC<insert()>メソッドを使用してインサートを実行した場合、 |
|
637 |
必要なパフォーマンスを得られない場合があるかもしれません。 |
|
638 |
C<insert()>メソッドは、SQL文とステートメントハンドルを |
|
639 |
毎回作成するためすこし遅いです。 |
|
640 | ||
641 |
そのような場合は、C<create_query()>メソッドによって |
|
642 |
クエリを用意しておくことができます。 |
|
643 |
|
|
644 |
my $query = $dbi->create_query( |
|
645 |
"insert into book {insert_param title author};" |
|
646 |
); |
|
647 | ||
648 |
戻り値はL<DBIx::Custom::Query>オブジェクトです。 |
|
649 |
このオブジェクトはSQL文とパラメータバインド時の列名を |
|
650 |
保持しています。またステートメントハンドルも保持しています。 |
|
651 | ||
652 |
{ |
|
653 |
sql => 'insert into book (title, author) values (?, ?);', |
|
654 |
columns => ['title', 'author'], |
|
655 |
sth => $sth |
|
656 |
} |
|
657 | ||
658 |
クエリオブジェクトを使って繰り返し実行するには次のようにします。 |
|
659 |
|
|
660 |
my $inputs = [ |
|
661 |
{title => 'Perl', author => 'Ken'}, |
|
662 |
{title => 'Good days', author => 'Mike'} |
|
663 |
]; |
|
664 |
|
|
665 |
foreach my $input (@$inputs) { |
|
666 |
$dbi->execute($query, $input); |
|
667 |
} |
|
668 | ||
669 |
C<execute>メソッドの第一引数にクエリオブジェトを渡すことができます。 |
|
670 |
これはC<insert()>メソッドよりも高速です。 |
|
671 | ||
672 |
=head2 7. その他の機能 |
|
673 | ||
674 |
=head3 トランザクション |
|
675 | ||
676 |
トランザクションを便利に利用するために、 |
|
677 |
C<begin_work()>、C<commit()>、C<rollback()> |
|
678 |
という三つのメソッドが容易されています。 |
|
679 |
これはL<DBI>の同名のメソッドと同じ機能を持ちます。 |
|
680 | ||
681 |
$dbi->begin_work; |
|
682 |
|
|
683 |
eval { |
|
684 |
$dbi->update(...); |
|
685 |
$dbi->update(...); |
|
686 |
}; |
|
687 |
|
|
688 |
if ($@) { |
|
689 |
$dbi->rollback; |
|
690 |
} |
|
691 |
else { |
|
692 |
$dbi->commit; |
|
693 |
} |
|
694 | ||
695 |
=head3 selectメソッドの結果クラスの変更 |
|
696 | ||
697 |
必要ならばC<select()>メソッドの結果クラスを変更することができます。 |
|
698 | ||
699 |
package Your::Result; |
|
700 |
use base 'DBIx::Custom::Result'; |
|
701 |
|
|
702 |
sub some_method { ... } |
|
703 | ||
704 |
1; |
|
705 |
|
|
706 |
package main; |
|
707 |
|
|
708 |
use Your::Result; |
|
709 |
|
|
710 |
my $dbi = DBIx::Custom->connect(...); |
|
711 |
$dbi->result_class('Your::Result'); |
|
712 | ||
713 |
=head3 L<DBIx::Custom::QueryBuilder>の機能の拡張 |
|
714 | ||
715 |
新しいタグが欲しい場合はL<DBIx::Custom::QueryBuilder>の機能を拡張 |
|
716 |
することができます。 |
|
717 | ||
718 |
my $dbi = DBIx::Custom->connect(...); |
|
719 |
$dbi->query_builder->register_tag_processor( |
|
720 |
name => sub { |
|
721 |
... |
|
722 |
} |
|
723 |
); |
|
724 | ||
725 |
=head3 ヘルパーメソッドの登録 |
|
726 | ||
727 |
ヘルパーメソッドを登録することができます。 |
|
728 | ||
729 |
$dbi->helper( |
|
730 |
update_or_insert => sub { |
|
731 |
my $self = shift; |
|
732 |
# do something |
|
733 |
}, |
|
734 |
find_or_create => sub { |
|
735 |
my $self = shift; |
|
736 |
# do something |
|
737 |
} |
|
738 |
); |
|
739 | ||
740 |
<helper()>メソッドで登録したメソッドは |
|
741 |
L<DBIx::Custom>オブジェクトから直接呼び出すことができます。 |
|
742 | ||
743 |
$dbi->update_or_insert; |
|
744 |
$dbi->find_or_create; |
|
745 | ||
746 |
=head3 ユーティリティメソッド(実験的) |
|
747 | ||
748 |
C<expand>メソッドを使用すると次のようなハッシュに含まれる |
|
749 |
テーブル名と列名を結合することができます。 |
|
750 | ||
751 |
my %expanded = $dbi->expand(\%source); |
|
752 | ||
753 |
以下のハッシュ |
|
754 | ||
755 |
{book => {title => 'Perl', author => 'Ken'}} |
|
756 | ||
757 |
は次のように展開されます。 |
|
758 | ||
759 |
('book.title' => 'Perl', 'book.author' => 'Ken') |
|
760 | ||
761 |
これはテーブル名を含むselect文で利用すると便利です。 |
|
762 | ||
763 |
my $param = {title => 'Perl', author => '%Ken%'}; |
|
764 |
$dbi->execute( |
|
765 |
'select * from book where {= book.title} && {like book.author};', |
|
766 |
param => {$dbi->expand({book => $param})} |
|
767 |
); |
|
768 | ||
769 |
=cut |