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