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', |
|
renamed dbi_options to dbi_o...
|
80 |
'issue_date' => {out => 'tp_to_date', in => 'date_to_tp'} |
updated document
|
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 | ||
updated document
|
164 |
まずL<DBIx::Custom>を読み込みます。 |
165 | ||
166 |
use DBIx::Custom; |
|
167 | ||
added experimental expand me...
|
168 |
L<DBIx::Custom>オブジェクトを生成し、データベースに接続するには |
169 |
C<connect()>メソッドを使用します。 |
|
170 | ||
updated document
|
171 |
my $dbi = DBIx::Custom->connect( |
172 |
data_source => "dbi:mysql:database=dbname", |
|
173 |
user => 'ken', |
|
174 |
password => '!LFKD%$&', |
|
175 |
dbi_options => {mysql_enable_utf8 => 1} |
|
176 |
); |
|
added experimental expand me...
|
177 | |
updated document
|
178 |
C<data_source>はデータベースシステムに応じたフォーマットで |
179 |
指定する必要があります。以下にデータベースごとのフォーマット |
|
180 |
方法のサンプルを掲載しておきます。 |
|
added experimental expand me...
|
181 | |
updated document
|
182 |
B<MySQL> |
added experimental expand me...
|
183 | |
deprecated DBIx::Custom::MyS...
|
184 |
"dbi:mysql:database=$database" |
185 |
"dbi:mysql:database=$database;host=$hostname;port=$port" |
|
added experimental expand me...
|
186 | |
updated document
|
187 |
B<SQLite> |
deprecated DBIx::Custom::MyS...
|
188 | |
189 |
"dbi:SQLite:dbname=$database" |
|
190 |
"dbi:SQLite:dbname=:memory:" |
|
191 | ||
updated document
|
192 |
B<PostgreSQL> |
deprecated DBIx::Custom::MyS...
|
193 | |
194 |
"dbi:Pg:dbname=$dbname" |
|
195 | ||
updated document
|
196 |
B<Oracle> |
deprecated DBIx::Custom::MyS...
|
197 | |
198 |
"dbi:Oracle:$dbname" |
|
199 |
"dbi:Oracle:host=$host;sid=$sid" |
|
200 | ||
updated document
|
201 |
B<ODBC(Microsoft Access)> |
deprecated DBIx::Custom::MyS...
|
202 | |
203 |
"dbi:ODBC:driver=Microsoft Access Driver (*.mdb);dbq=hoge.mdb" |
|
204 | ||
updated document
|
205 |
B<ODBC(SQL Server)> |
deprecated DBIx::Custom::MyS...
|
206 | |
207 |
"dbi:ODBC:driver={SQL Server};Server=(local);database=test;Trusted_Connection=yes;AutoTranslate=No;" |
|
added experimental expand me...
|
208 | |
updated document
|
209 |
また認証が求められる場合は、C<user>とC<password>ユーザ名と |
210 |
パスワードを指定する必要があります。 |
|
211 | ||
added experimental expand me...
|
212 |
L<DBIx::Custom>はL<DBI>のラッパです。 |
updated document
|
213 |
L<DBI>のデータベースハンドルはC<dbh>で取得することができます。 |
added experimental expand me...
|
214 | |
215 |
my $dbh = $dbi->dbh; |
|
216 | ||
updated document
|
217 |
L<DBIx::Custom>ではデータベースハンドル属性にはデフォルトで次のものが設定されます。 |
added experimental expand me...
|
218 |
|
219 |
$dbi->dbh->{RaiseError} = 1; |
|
220 |
$dbi->dbh->{PrintError} = 0; |
|
221 |
$dbi->dbh->{AutoCommit} = 1; |
|
222 | ||
223 |
この設定を行っているので、致命的なエラーが起こると、 |
|
224 |
例外が発生しプログラムは終了します。 |
|
225 |
またクエリが発行されると自動的にコミットされます。 |
|
226 | ||
updated document
|
227 |
=head2 2. 挿入、更新、削除、選択のためのメソッド |
added experimental expand me...
|
228 | |
229 |
L<DBIx::Custom>は、 |
|
230 |
C<insert()>、C<update()>、C<delete()>、C<select()> |
|
updated document
|
231 |
のような挿入、更新、削除、選択を行うためのメソッドを持っています。 |
232 |
簡単なことをを行うのであれば、SQLを自分で記述する必要がありません。 |
|
added experimental expand me...
|
233 | |
234 |
=head3 C<insert()> |
|
235 | ||
updated document
|
236 |
データベースにデータを挿入するにはC<insert()>を使用します。 |
added experimental expand me...
|
237 | |
remove DBIx::Custom::Model
|
238 |
$dbi->insert(table => 'book', |
added experimental expand me...
|
239 |
param => {title => 'Perl', author => 'Ken'}); |
240 | ||
updated document
|
241 |
C<table>にはテーブル名、C<param>には挿入したいデータを指定します。 |
added experimental expand me...
|
242 | |
updated document
|
243 |
次のSQLが発行されます。 |
244 | ||
245 |
insert into (title, author) values (?, ?); |
|
added experimental expand me...
|
246 | |
247 |
=head3 C<update()> |
|
248 | ||
updated document
|
249 |
データベースのデータを更新するには、C<update()>を使用します。 |
added experimental expand me...
|
250 | |
remove DBIx::Custom::Model
|
251 |
$dbi->update(table => 'book', |
added experimental expand me...
|
252 |
param => {title => 'Perl', author => 'Ken'}, |
253 |
where => {id => 5}); |
|
254 | ||
updated document
|
255 |
C<table>にはテーブル名、C<param>には挿入したいデータ、C<where>には |
256 |
条件を指定します。 |
|
added experimental expand me...
|
257 | |
updated document
|
258 |
次のSQLが発行されます。 |
259 | ||
260 |
update book set title = ?, author = ?; |
|
added experimental expand me...
|
261 | |
262 |
C<update>メソッドは安全のため |
|
263 |
where句のないSQLを発行することを許可していません。 |
|
264 |
もしすべての行を更新したい場合は |
|
updated document
|
265 |
C<update_all()>を使用してください。 |
added experimental expand me...
|
266 | |
remove DBIx::Custom::Model
|
267 |
$dbi->update_all(table => 'book', |
added experimental expand me...
|
268 |
param => {title => 'Perl', author => 'Ken'}); |
269 | ||
270 |
=head3 C<delete()> |
|
271 | ||
updated document
|
272 |
データベースのデータを1件削除するには、C<delete()>を使用します。 |
added experimental expand me...
|
273 | |
remove DBIx::Custom::Model
|
274 |
$dbi->delete(table => 'book', |
added experimental expand me...
|
275 |
where => {author => 'Ken'}); |
276 | ||
updated document
|
277 |
C<table>にはテーブル名、C<where>には条件を指定します。 |
added experimental expand me...
|
278 | |
updated document
|
279 |
次のSQLが発行されます。 |
280 | ||
281 |
delete from book where id = ?; |
|
added experimental expand me...
|
282 | |
283 |
C<delete>メソッドは安全のため |
|
284 |
where句のないSQLを発行することを許可していません。 |
|
285 |
もしすべての行を削除したい場合は |
|
updated document
|
286 |
C<delete_all()>を使用してください。 |
added experimental expand me...
|
287 | |
remove DBIx::Custom::Model
|
288 |
$dbi->delete_all(table => 'book'); |
added experimental expand me...
|
289 | |
290 |
=head3 C<select()> |
|
291 | ||
updated document
|
292 |
行を選択するにはC<select()>を使用します。 |
added experimental expand me...
|
293 | |
remove DBIx::Custom::Model
|
294 |
my $result = $dbi->select(table => 'book'); |
added experimental expand me...
|
295 | |
updated document
|
296 |
C<table>だけを指定して、他の条件を指定しない場合は次のSQLが発行されます。 |
added experimental expand me...
|
297 | |
updated document
|
298 |
select * from book; |
added experimental expand me...
|
299 | |
300 |
C<select()>メソッドの戻り値はL<DBIx::Custom::Result> |
|
updated document
|
301 |
オブジェクトです。行をフェッチするにはC<fetch()>を使用します。 |
added experimental expand me...
|
302 | |
303 |
while (my $row = $result->fetch) { |
|
304 |
my $title = $row->[0]; |
|
305 |
my $author = $row->[1]; |
|
306 |
} |
|
307 | ||
updated document
|
308 |
L<DBIx::Custom::Result>についてはこの後L<3. 行のフェッチ/"3. 行のフェッチ">で詳しく扱います。 |
309 | ||
310 |
さまざまなC<select()>の使い方を見ていきましょう。 |
|
added experimental expand me...
|
311 |
次のC<select>は行の名前とwhere句を指定したものです。 |
312 | ||
313 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
314 |
table => 'book', |
updated document
|
315 |
column => ['author', 'title'], |
added experimental expand me...
|
316 |
where => {author => 'Ken'} |
317 |
); |
|
318 | ||
updated document
|
319 |
C<column>には列名を、C<where>には条件を指定することができます。 |
320 |
次のSQLが発行されます。 |
|
321 | ||
322 |
select author, title from book where author = ?; |
|
added experimental expand me...
|
323 | |
updated document
|
324 |
テーブルを結合したい場合ははC<relation>にテーブルの |
325 |
関係を記述します。 |
|
added experimental expand me...
|
326 | |
327 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
328 |
table => ['book', 'rental'], |
updated document
|
329 |
where => {book.name => 'Perl'}, |
remove DBIx::Custom::Model
|
330 |
relation => {'book.id' => 'rental.book_id'} |
added experimental expand me...
|
331 |
); |
332 | ||
updated document
|
333 |
bookテーブルのid列とrentalテーブルのbook_idが関連付けられます。 |
334 |
次のSQLが発行されます。 |
|
added experimental expand me...
|
335 | |
updated document
|
336 |
select * from book, rental where book.name = ? and book.id = rental.book_id; |
added experimental expand me...
|
337 | |
updated document
|
338 |
SQL文の末尾に文字列を追加したい場合は<append>を使用します。 |
added experimental expand me...
|
339 | |
340 |
my $result = $dbi->select( |
|
remove DBIx::Custom::Model
|
341 |
table => 'book', |
added experimental expand me...
|
342 |
where => {author => 'Ken'}, |
updated document
|
343 |
append => 'for update', |
added experimental expand me...
|
344 |
); |
345 | ||
updated document
|
346 |
次のSQLが発行されます。 |
updated document
|
347 | |
updated document
|
348 |
select * book where author = ? for update; |
updated document
|
349 | |
updated document
|
350 |
またC<append>は、C<select>だけでなくC<insert()>、C<update()>、C<update_all()> |
351 |
C<delete()>、C<delete_all()>、C<select()>で使用することもできます。 |
|
updated document
|
352 | |
removed experimental txn_sco...
|
353 |
=head4 execute |
354 | ||
355 |
任意のSQLを実行するにはexecuteメソッドを使用します。 |
|
356 | ||
357 |
$dbi->execute("select * from book;"); |
|
358 | ||
359 |
C<execute()>はL<DBIx::Custom>の根幹のメソッドでありタグを展開します。 |
|
360 | ||
361 |
$dbi->execute( |
|
362 |
"select * from book {= title} and {= author};" |
|
363 |
param => {title => 'Perl', author => 'Ken'} |
|
364 |
); |
|
365 | ||
366 |
上記のタグを含んだSQLは次のように展開されます。 |
|
367 | ||
368 |
select * from book title = ? and author = ?; |
|
369 | ||
370 |
SQLが実行されるときにプレースホルダ(?)に対応する位置にtitleとauthor |
|
371 |
の値がが自動的に埋め込まれます。 |
|
372 | ||
373 |
タグについてはL<5. タグ/"5. タグ">で詳しく解説しますが、 |
|
374 |
ひとつの注意点があります。 |
|
375 |
タグを展開するためにC<{>とC<}>は予約語になっています。 |
|
376 |
もし利用したい場合は直前に\をおいてエスケープを行う必要があります。 |
|
377 | ||
378 |
$dbi->execute("... \\{ ... \\} ..."); |
|
379 | ||
380 |
\自体がPerlのエスケープ文字ですので、二つ必要になるという点に注意してください。 |
|
381 | ||
382 |
またexecuteのキュートな機能として、SQLの最後にセミコロンをおかなくても |
|
383 |
かまいません。 |
|
384 | ||
385 |
$dbi->execute('select * from book'); |
|
386 | ||
updated document
|
387 |
=head2 3. 行のフェッチ |
388 | ||
updated document
|
389 |
C<select()>メソッドの戻り値はL<DBIx::Custom::Result>オブジェクトです。 |
390 |
L<DBIx::Custom::Result>には行をフェッチするためのさまざまなメソッドが |
|
updated document
|
391 |
用意されています。 |
392 | ||
393 |
=head3 C<fetch> |
|
394 | ||
updated document
|
395 |
一行フェッチして配列のリファレンスに格納するにはC<fetch()>を使用します。 |
updated document
|
396 | |
397 |
while (my $row = $result->fetch) { |
|
updated document
|
398 |
my $title = $row->[0]; |
399 |
my $author = $row->[1]; |
|
updated document
|
400 |
} |
401 | ||
updated document
|
402 |
whileループを使って、すべての行を取得することができます。 |
403 | ||
updated document
|
404 |
=head3 C<fetch_first> |
405 | ||
updated document
|
406 |
一行だけフェッチして配列のリファレンスに格納するにはC<fetch_first()> |
407 |
を使用します。 |
|
updated document
|
408 | |
409 |
my $row = $result->fetch_first; |
|
410 | ||
updated document
|
411 |
一行のフェッチが終わった後はそれ以上フェッチできなくなります。 |
412 |
内部的には1行のフェッチが終わった後に |
|
413 |
ステートメントハンドルのC<finish()>が実行されます。 |
|
updated document
|
414 | |
415 |
=head3 C<fetch_multi> |
|
416 | ||
updated document
|
417 |
複数行をフェッチして配列のリファレンスを要素に持つ |
418 |
配列のリファレンスに格納するにはC<fetch_multi()>を使用します。 |
|
updated document
|
419 | |
updated document
|
420 |
while (my $rows = $result->fetch_multi(2)) { |
421 |
my $title0 = $rows->[0][0]; |
|
422 |
my $author0 = $rows->[0][1]; |
|
423 |
|
|
424 |
my $title1 = $rows->[1][0]; |
|
425 |
my $author1 = $rows->[1][1]; |
|
updated document
|
426 |
} |
427 | ||
updated document
|
428 |
引数には取り出したい行数を指定します。 |
429 | ||
430 |
指定した行を格納した次のようなデータを取得できます。 |
|
431 | ||
432 |
[ |
|
433 |
['Perl', 'Ken'], |
|
434 |
['Ruby', 'Mark'] |
|
435 |
] |
|
436 | ||
updated document
|
437 |
=head3 C<fetch_all> |
438 | ||
updated document
|
439 |
すべての行をフェッチして配列のリファレンスを要素に持つ |
440 |
配列のリファレンスに格納するにはC<fetch_all()>を使用します。 |
|
updated document
|
441 | |
442 |
my $rows = $result->fetch_all; |
|
443 | ||
updated document
|
444 |
すべての行を格納した次のようなデータを取得できます。 |
445 | ||
446 |
[ |
|
447 |
['Perl', 'Ken'], |
|
448 |
['Ruby', 'Mark'] |
|
449 |
] |
|
450 | ||
updated document
|
451 |
=head3 C<fetch_hash> |
452 | ||
updated document
|
453 |
一行フェッチしてハッシュのリファレンスに格納するにはC<fetch_hash()>を使用します。 |
updated document
|
454 | |
455 |
while (my $row = $result->fetch_hash) { |
|
456 |
my $title = $row->{title}; |
|
457 |
my $author = $row->{author}; |
|
458 |
} |
|
459 | ||
460 |
=head3 C<fetch_hash_first> |
|
461 | ||
updated document
|
462 |
一行だけフェッチしてハッシュのリファレンスに格納するには |
463 |
C<fetch_hash_first()>を使用します。 |
|
updated document
|
464 | |
465 |
my $row = $result->fetch_hash_first; |
|
466 | ||
updated document
|
467 |
一行のフェッチが終わった後はそれ以上フェッチできなくなります。 |
468 |
内部的には1行のフェッチが終わった後に |
|
469 |
ステートメントハンドルのC<finish()>が実行されます。 |
|
updated document
|
470 | |
471 |
=head3 C<fetch_hash_multi> |
|
472 | ||
updated document
|
473 |
複数行をフェッチしてハッシュのリファレンスを要素に持つ |
474 |
配列のリファレンスに格納するにはC<fetch_hash_multi()> |
|
475 |
を使用します。 |
|
updated document
|
476 | |
477 |
while (my $rows = $result->fetch_hash_multi(5)) { |
|
updated document
|
478 |
my $title0 = $rows->[0]{title}; |
479 |
my $author0 = $rows->[0]{author}; |
|
480 |
my $title1 = $rows->[1]{title}; |
|
481 |
my $author1 = $rows->[1]{author}; |
|
updated document
|
482 |
} |
483 | ||
updated document
|
484 |
引数には取り出したい行数を指定します。 |
485 | ||
486 |
指定した行を格納した次のようなデータを取得できます。 |
|
487 | ||
488 |
[ |
|
489 |
{title => 'Perl', author => 'Ken'}, |
|
490 |
{title => 'Ruby', author => 'Mark'} |
|
491 |
] |
|
492 | ||
updated document
|
493 |
=head3 C<fetch_all> |
494 | ||
updated document
|
495 |
すべての行をフェッチしてハッシュのリファレンスを要素に持つ |
496 |
配列のリファレンスに格納するにはC<fetch_hash_all()> |
|
497 |
を使用します。 |
|
updated document
|
498 | |
499 |
my $rows = $result->fetch_hash_all; |
|
500 | ||
updated document
|
501 |
すべての行を格納した次のようなデータを取得できます。 |
502 | ||
503 |
[ |
|
504 |
{title => 'Perl', author => 'Ken'}, |
|
505 |
{title => 'Ruby', author => 'Mark'} |
|
506 |
] |
|
507 | ||
508 |
=head3 sth |
|
509 | ||
510 |
ステートメントハンドルに直接アクセスしたい場合は |
|
511 |
<sth>で取得することができます。 |
|
updated document
|
512 | |
513 |
my $sth = $result->sth; |
|
514 | ||
updated document
|
515 |
フェッチのパフォーマンスが用件を満たさないときには、 |
516 |
ステートメントハンドルから |
|
517 |
利用できる速度の速いメソッドを利用することができます。 |
|
518 | ||
renamed dbi_options to dbi_o...
|
519 |
=head2 4. フィルタリング |
520 | ||
521 |
データベースにデータを登録するときやデータベースからデータを取得する |
|
522 |
ときに自動的に値の変換を行いたい場合が多いと思います。 |
|
523 |
たとえば、日付を表現する列の場合は、 |
|
524 |
データベースに登録する場合はL<Time::Piece>オブジェクトから |
|
525 |
データベースの日付のフォーマットに、 |
|
526 |
データベースからデータを取得するときは、その逆を行えると便利です。 |
|
527 | ||
528 |
=head3 フィルタの登録 |
|
529 | ||
530 |
フィルタを登録するにはC<register_filter()>を使用します。 |
|
531 | ||
532 |
$dbi->register_filter( |
|
533 |
# Time::Piece object to DATE format |
|
534 |
tp_to_date => sub { |
|
535 |
my $date = shift; |
|
536 | ||
537 |
return '0000-00-00' unless $tp; |
|
538 |
return $tp->strftime('%Y-%m-%d'); |
|
539 |
}, |
|
540 |
|
|
541 |
# DATE to Time::Piece object |
|
542 |
date_to_tp => sub { |
|
543 |
my $date = shift; |
|
544 | ||
545 |
return if $date eq '0000-00-00'; |
|
546 |
return Time::Piece->strptime($date, '%Y-%m-%d'); |
|
547 |
}, |
|
548 |
); |
|
549 | ||
550 |
登録したフィルタはC<apply_filter()>などで利用することができます。 |
|
551 | ||
552 |
=head3 フィルタの適用 |
|
553 | ||
554 |
作成したフィルタを適用するには、C<apply_filter()>を使用します。 |
|
555 | ||
556 |
$dbi->apply_filter('book', |
|
557 |
issue_date => {out => 'tp_to_date', in => 'date_to_tp'}, |
|
558 |
first_issue_date => {out => 'tp_to_date', in => 'date_to_tp'} |
|
559 |
); |
|
560 | ||
561 |
第一引数はテーブル名です。第二引数以降は、列名とフィルタルールのペアを記述します。 |
|
562 |
フィルタルールのoutには、データベースにデータを送信するときに適用するフィルタを、 |
|
563 |
フィルタルールのinには、データベースからデータを取得するときに適用するフィルタを |
|
564 |
記述します。outがデータベースに送信する方向、inがデータベースから取り出す方向です。 |
|
565 |
フィルタには、C<register_filter>で登録したフィルタ名の他に、コードリファレンスを |
|
566 |
指定することもできます。 |
|
567 | ||
568 |
issue_date => {out => sub { ... }, in => sub { ... }} |
|
569 | ||
570 |
適用されたフィルタはC<insert()>、C<update()>、C<update_all()>、C<delete()>、 |
|
571 |
C<delete_all()>、C<select()>で有効になります。 |
|
572 | ||
573 |
my $tp = Time::Piece->strptime('2010/10/14', '%Y/%m/%d'); |
|
574 |
my $result = $dbi->select(table => 'book', where => {issu_date => $tp}); |
|
575 | ||
576 |
データベースにデータが送信されるときに、L<Time::Piece>オブジェクトは |
|
577 |
データベースの日付のフォーマット「2010-10-14」に変換されます。 |
|
578 | ||
579 |
また逆にデータをフェッチするときには、データベースの日付のフォーマットは |
|
580 |
タイムピースオブジェクトに変換されます。 |
|
581 | ||
582 |
my $row = $resutl->fetch_hash_first; |
|
583 |
my $tp = $row->{issue_date}; |
|
584 | ||
585 |
このような自動的に実行されるフィルタを登録できることがL<DBIx::Custom>の |
|
586 |
特徴のひとつです。 |
|
587 | ||
removed experimental txn_sco...
|
588 |
=head3 個別のフィルタの適用 |
renamed dbi_options to dbi_o...
|
589 | |
590 |
C<apply_filter()>を使って最初にすべてのテーブルの列について |
|
removed experimental txn_sco...
|
591 |
フィルタを定義することもできますが、 |
592 |
個別にフィルタを適用することもできます。 |
|
renamed dbi_options to dbi_o...
|
593 |
個別のフィルタはC<apply_filter()>で適用したフィルタを上書きます。 |
removed experimental txn_sco...
|
594 |
個別のフィルタはSQLのasを使って、列の別名を作成する必要がある場合に活躍します。 |
595 | ||
596 |
データベースに送信する場合に、個別のフィルタを適用するには、各メソッドの |
|
597 |
C<filter>オプションを使用します。個別のフィルタは、C<insert()>、C<update()>、 |
|
598 |
C<update_all()>、C<delete()>、C<delete_all()>、C<select()>、C<execute()> |
|
599 |
で使用することができます。 |
|
renamed dbi_options to dbi_o...
|
600 | |
removed experimental txn_sco...
|
601 |
C<insert()>の例を示します。 |
602 | ||
603 |
$dbi->insert( |
|
604 |
table => 'book', |
|
605 |
param => {issue_date => $tp, first_issue_date => $tp}, |
|
606 |
filter => {issue_date => 'tp_to_date', first_issue_date => 'tp_to_date'} |
|
607 |
); |
|
608 | ||
609 |
C<execute()>の例を示します。 |
|
610 | ||
611 |
my $sql = <<"EOS"; |
|
612 |
select YEAR(issue_date) as issue_year |
|
613 |
from book |
|
614 |
where YEAR(issue_date) = {? issue_year} |
|
615 |
EOS |
|
616 |
|
|
617 |
my $result = $dbi->execute( |
|
618 |
$sql, |
|
619 |
param => {issue_year => '2010'}, |
|
620 |
filter => {issue_year => 'tp_to_year'} |
|
621 |
); |
|
622 | ||
623 |
これはC<filter>を使う良くある例です。issue_dateの変換についてはC<apply_filter()> |
|
624 |
で登録してあるのですが、新しく作成した列であるissue_yearについては、 |
|
625 |
何の変換も登録されていません。ですので、個別にフィルタを設定しています。 |
|
626 | ||
627 |
また反対に行をフェッチするときにも個別のフィルタを適用することができます。 |
|
628 |
フィルタを適用するには、 |
|
renamed dbi_options to dbi_o...
|
629 |
C<DBIx::Custom::Result>クラスのC<filter>メソッドを使用します。 |
630 | ||
removed experimental txn_sco...
|
631 |
$result->filter(issue_year => 'year_to_tp'); |
632 | ||
633 |
頻繁に利用するのであれば、個別に登録するよりもC<apply_filter()>で登録 |
|
634 |
しておいたほうが便利でしょう。C<apply_filter()>は存在しない列に対しても |
|
635 |
フィルタを適用できるからです。 |
|
636 | ||
637 |
$dbi->apply_filter('book', |
|
638 |
'issue_year' => {out => 'tp_to_year', in => 'year_to_tp'} |
|
639 |
); |
|
640 | ||
641 |
C<DBIx::Custom::Result>ではさらに最後にもう一度、フィルタを追加で |
|
642 |
登録することができます。たとえばHTMLに出力したい場合に、Time::Piece |
|
643 |
オブジェクトから読みやすい記述に変換することができます。 |
|
644 |
最後のフィルタを登録するには、C<end_filter()>を使用します。 |
|
645 | ||
646 |
$result->end_filter(issue_date => sub { |
|
647 |
my $tp = shift; |
|
648 |
|
|
649 |
return '' unless $tp; |
|
650 |
return $tp->strftime('%Y/%m/%d %h:%m:%s (%a)'); |
|
651 |
}); |
|
652 | ||
653 |
日付を見やすい形にフォーマットすることができます。 |
|
654 | ||
655 |
フィルタはフェッチを行う前に登録しておく必要があることに |
|
656 |
注意してください。 |
|
657 | ||
658 |
$result->filter(...); |
|
659 |
$result->end_filter(...); |
|
660 |
my $row = $result->fetch_hash_first; |
|
661 | ||
662 |
=head3 列の情報を元にフィルタを適用する |
|
663 | ||
664 |
日付型の列は手動で設定しなくても、自動的に設定できると便利です。 |
|
665 |
このためにデータベースのテーブルの列のすべての情報を |
|
666 |
順番に処理するためのC<each_column()>があります。 |
|
667 | ||
668 |
$dbi->each_column( |
|
669 |
sub { |
|
670 |
my ($self, $table, $column, $info) = @_; |
|
671 |
|
|
672 |
my $type = $info->{TYPE_NAME}; |
|
673 |
|
|
674 |
my $filter = $type eq 'DATE' ? {out => 'tp_to_date', in => 'date_to_tp'} |
|
675 |
: $type eq 'DATETIME' ? {out => 'tp_to_datetime', in => 'datetime_to_tp'} |
|
676 |
: undef; |
|
677 |
|
|
678 |
$self->apply_filter($table, $column, $filter) |
|
679 |
if $filter; |
|
680 |
} |
|
681 |
); |
|
renamed dbi_options to dbi_o...
|
682 | |
removed experimental txn_sco...
|
683 |
each_columnはコールバックを受け取ります。コールバックの引数は |
684 |
順番にL<DBIx::Custom>オブジェクト、テーブル名、列名、列の情報です。 |
|
685 |
列の型名の情報をもとに自動的に、フィルタを適用しています。 |
|
686 | ||
687 |
ひとつの注意点としてコールバックの中から、コールバックの外側 |
|
688 |
の変数を参照しないように注意してください。each_columnは |
|
689 |
高々1回だけ実行されるだけなので、ほとんどの場合問題ありませんが、 |
|
690 |
循環参照によるメモリリークが発生してしまう可能性を持っているからです。 |
|
renamed dbi_options to dbi_o...
|
691 | |
692 |
=head2 5. タグ |
|
updated document
|
693 | |
694 |
L<DBIx::Custom>はハッシュパラメタバインドを提供します。 |
|
695 | ||
696 |
まず最初にL<DBI>による通常のパラメタバインドをご覧ください。 |
|
697 | ||
698 |
use DBI; |
|
699 |
my $dbh = DBI->connect(...); |
|
700 |
my $sth = $dbh->prepare( |
|
701 |
"select * from book where author = ? and title like ?;" |
|
702 |
); |
|
703 |
$sth->execute('Ken', '%Perl%'); |
|
704 | ||
705 |
これはデータベースシステムがSQLをキャッシュすることができ、 |
|
706 |
パラメータは自動的にクォートされるので、 |
|
707 |
パフォーマンス面でも、セキュリティ面でも |
|
708 |
とても良い方法です。 |
|
709 | ||
710 | ||
711 |
L<DBIx::Custom>はこれを改善して、ハッシュで |
|
712 |
パラメタを指定できるようにしました。 |
|
713 | ||
714 |
my $result = $dbi->execute( |
|
715 |
"select * from book where {= author} and {like title};" |
|
716 |
param => {author => 'Ken', title => '%Perl%'} |
|
717 |
); |
|
718 | ||
719 |
C<{= author}>とC<{like title}>はタグと呼ばれます。 |
|
720 |
タグは内部ではプレースホルダを含む文字列に置き換えられます。 |
|
721 | ||
722 |
select * from book where {= author} and {like title} |
|
723 | ||
724 |
という文は以下のSQLに置き換えられます。 |
|
725 | ||
726 |
select * from book where author = ? and title like ?; |
|
727 | ||
728 |
このようにタグを使ってSQL文を表現するのがL<DBIx::Custom>の |
|
729 |
特徴です。以下のタグが利用可能です。 |
|
730 | ||
731 |
[TAG] [REPLACED] |
|
732 |
{? NAME} -> ? |
|
733 |
{= NAME} -> NAME = ? |
|
734 |
{<> NAME} -> NAME <> ? |
|
735 |
|
|
736 |
{< NAME} -> NAME < ? |
|
737 |
{> NAME} -> NAME > ? |
|
738 |
{>= NAME} -> NAME >= ? |
|
739 |
{<= NAME} -> NAME <= ? |
|
740 |
|
|
741 |
{like NAME} -> NAME like ? |
|
742 |
{in NAME COUNT} -> NAME in [?, ?, ..] |
|
743 |
|
|
744 |
{insert_param NAME1 NAME2} -> (NAME1, NAME2) values (?, ?) |
|
745 |
{update_param NAME1 NAME2} -> set NAME1 = ?, NAME2 = ? |
|
746 | ||
747 |
これらの変換はL<DBIx::Custom::QueryBuilder>によって行われます。 |
|
748 | ||
749 |
C<{>とC<}>は予約語です。これらの文字を使いたい場合は |
|
750 |
「\」を使ってエスケープする必要があります。 |
|
751 |
'\'はPerlのエスケープ文字なので、 |
|
752 |
エスケープするためには'\\'と書く必要があることに注意 |
|
753 |
してください。 |
|
754 | ||
755 |
'select * from book \\{ something statement \\}' |
|
756 | ||
removed experimental txn_sco...
|
757 |
=head3 L<DBIx::Custom::QueryBuilder>の機能の拡張 |
758 | ||
759 |
新しいタグが欲しい場合はL<DBIx::Custom::QueryBuilder>の機能を拡張 |
|
760 |
することができます。 |
|
761 | ||
762 |
my $dbi = DBIx::Custom->connect(...); |
|
763 |
$dbi->register_tag( |
|
764 |
name => sub { |
|
765 |
... |
|
766 |
} |
|
767 |
); |
|
768 | ||
769 |
=head2 6. Where句の動的な生成 |
|
770 | ||
771 |
=head2 7. パフォーマンスの改善 |
|
updated document
|
772 | |
773 |
=head3 シュガーメソッドを使わない |
|
774 | ||
775 |
もしC<insert()>メソッドを使用してインサートを実行した場合、 |
|
776 |
必要なパフォーマンスを得られない場合があるかもしれません。 |
|
777 |
C<insert()>メソッドは、SQL文とステートメントハンドルを |
|
778 |
毎回作成するためすこし遅いです。 |
|
779 | ||
780 |
そのような場合は、C<create_query()>メソッドによって |
|
781 |
クエリを用意しておくことができます。 |
|
782 |
|
|
783 |
my $query = $dbi->create_query( |
|
784 |
"insert into book {insert_param title author};" |
|
785 |
); |
|
786 | ||
787 |
戻り値はL<DBIx::Custom::Query>オブジェクトです。 |
|
788 |
このオブジェクトはSQL文とパラメータバインド時の列名を |
|
789 |
保持しています。またステートメントハンドルも保持しています。 |
|
790 | ||
791 |
{ |
|
792 |
sql => 'insert into book (title, author) values (?, ?);', |
|
793 |
columns => ['title', 'author'], |
|
794 |
sth => $sth |
|
795 |
} |
|
796 | ||
797 |
クエリオブジェクトを使って繰り返し実行するには次のようにします。 |
|
798 |
|
|
799 |
my $inputs = [ |
|
800 |
{title => 'Perl', author => 'Ken'}, |
|
801 |
{title => 'Good days', author => 'Mike'} |
|
802 |
]; |
|
803 |
|
|
804 |
foreach my $input (@$inputs) { |
|
805 |
$dbi->execute($query, $input); |
|
806 |
} |
|
807 | ||
808 |
C<execute>メソッドの第一引数にクエリオブジェトを渡すことができます。 |
|
809 |
これはC<insert()>メソッドよりも高速です。 |
|
810 | ||
removed experimental txn_sco...
|
811 |
=head2 8. その他の機能 |
updated document
|
812 | |
813 |
=head3 トランザクション |
|
814 | ||
815 |
トランザクションを便利に利用するために、 |
|
816 |
C<begin_work()>、C<commit()>、C<rollback()> |
|
817 |
という三つのメソッドが容易されています。 |
|
818 |
これはL<DBI>の同名のメソッドと同じ機能を持ちます。 |
|
renamed dbi_options to dbi_o...
|
819 |
fc |
updated document
|
820 |
$dbi->begin_work; |
821 |
|
|
822 |
eval { |
|
823 |
$dbi->update(...); |
|
824 |
$dbi->update(...); |
|
825 |
}; |
|
826 |
|
|
827 |
if ($@) { |
|
828 |
$dbi->rollback; |
|
829 |
} |
|
830 |
else { |
|
831 |
$dbi->commit; |
|
832 |
} |
|
833 | ||
834 |
=head3 selectメソッドの結果クラスの変更 |
|
835 | ||
836 |
必要ならばC<select()>メソッドの結果クラスを変更することができます。 |
|
837 | ||
838 |
package Your::Result; |
|
839 |
use base 'DBIx::Custom::Result'; |
|
840 |
|
|
841 |
sub some_method { ... } |
|
842 | ||
843 |
1; |
|
844 |
|
|
845 |
package main; |
|
846 |
|
|
847 |
use Your::Result; |
|
848 |
|
|
849 |
my $dbi = DBIx::Custom->connect(...); |
|
850 |
$dbi->result_class('Your::Result'); |
|
851 | ||
852 |
=head3 ヘルパーメソッドの登録 |
|
853 | ||
854 |
ヘルパーメソッドを登録することができます。 |
|
855 | ||
856 |
$dbi->helper( |
|
857 |
update_or_insert => sub { |
|
858 |
my $self = shift; |
|
859 |
# do something |
|
860 |
}, |
|
861 |
find_or_create => sub { |
|
862 |
my $self = shift; |
|
863 |
# do something |
|
864 |
} |
|
865 |
); |
|
866 | ||
867 |
<helper()>メソッドで登録したメソッドは |
|
868 |
L<DBIx::Custom>オブジェクトから直接呼び出すことができます。 |
|
869 | ||
870 |
$dbi->update_or_insert; |
|
871 |
$dbi->find_or_create; |
|
872 | ||
renamed dbi_options to dbi_o...
|
873 |
=head3 ユーティリティメソッド |
updated document
|
874 | |
875 |
C<expand>メソッドを使用すると次のようなハッシュに含まれる |
|
876 |
テーブル名と列名を結合することができます。 |
|
877 | ||
878 |
my %expanded = $dbi->expand(\%source); |
|
879 | ||
880 |
以下のハッシュ |
|
881 | ||
882 |
{book => {title => 'Perl', author => 'Ken'}} |
|
883 | ||
884 |
は次のように展開されます。 |
|
885 | ||
886 |
('book.title' => 'Perl', 'book.author' => 'Ken') |
|
887 | ||
888 |
これはテーブル名を含むselect文で利用すると便利です。 |
|
889 | ||
890 |
my $param = {title => 'Perl', author => '%Ken%'}; |
|
891 |
$dbi->execute( |
|
892 |
'select * from book where {= book.title} && {like book.author};', |
|
893 |
param => {$dbi->expand({book => $param})} |
|
894 |
); |
|
895 | ||
896 |
=cut |