VB を使用した蔵書管理 (Matt Gertz)
白状しますが、私はデータベースに疎い人間です。これまでさまざまなコーディングを行ってきましたが、なぜか、データベース コーディングの主要な作業に直接かかわることはありませんでした。自分のコードでデータ キャッシュ メカニズムが必要になると、"自作" して済ませる傾向にありました。そういう訳で、VS2008 の LINQ の作業を始めたときは、データ プログラミングのノウハウを学ぶチャンスだと思って張り切りました。それなのに、数週間も経たないうちにコンパイラ担当から開発マネージャに昇格してしまって、この技術を習熟しようと努力はしたものの、システムの中核まで掘り下げて学ぶ時間はありませんでした。
コード自体には直接携わっていないのですが、SQL Server Compact Edition と LINQ を使ってデータ アプリケーションを簡単にコーディングできるようになりました。この週末、膨れ上がる一方の蔵書の管理に、この機能を使ってみることにしました。私には、本を買いすぎるという悪癖があります。文学書、哲学書、物理学の本、古典といった高尚な書籍から、ありふれた SF まで、書店に入ると山ほど買わずにいられないのです。ネット書店が溢れている今では、書店に行かないようにしても、家中に本が溜まってしまいます (そのうちのいくつかは、どうにか時間を見つけて読むことができるという状態です)。
蔵書が多いと、買った本を忘れてしまうという、大きな問題が生じます。1980 年代には Hypercard のスタックを作って蔵書を管理していましたが、Macintosh Centris 650 をリサイクルに出して以来、その後に使ったどの Windows コンピュータでもこうしたファイルを作りませんでした。今回 VS2008 を入れたので、試してみようと思い立ちました。
データベースを作成する
私は SQL Compact Edition がとても気に入っています。これは VS2008 で既定でインストールされますが、このサイト から無料でダウンロードすることもできます。ローカル コンピュータ上のファイルに含まれるすべての内容を格納し、そのデータを他のコンピュータに簡単に移動できるので、私にはこれが最高に役立つのです。既製のデータベースを持っていなくても、これを使うと簡単に作成できます。さらに、Visual Studio 内からデータベースを作成することもできます。
1. Launch Visual Studio 2008 を起動します。
2. [表示]、[サーバー エクスプローラ] の順に選択します。
3. ツール ウィンドウが表示されたら、[接続の追加] コマンドを右クリックします。
4. これで、データ ソースを選択するダイアログ ボックスが表示されます。
a. [SQL Server Compact 3.5 (.NET Framework)] および [マイ コンピュータ] を選択します。
b. [接続のプロパティ] 領域で [作成] をクリックして、新しいデータベースを作成します。
c. データベース ファイルの名前を指定するダイアログ ボックスが表示されます (私は "GertzLibrary" という名前を付けました)。ここでパスワードを指定することもできますが、私の蔵書データベースは機密情報ではないので、この手順は省きました。ここまでの手順が完了したら [OK] をクリックします。これでデータベースの作成が終わりました。
d. 最初のダイアログ ボックスに戻ったら、[OK] をクリックする前に、必要に応じてパスワードを追加する必要があります。必要でなければ [OK] をクリックするだけです。これで、データベースへの接続が作成されます。
5. 作成したデータベースがサーバー エクスプローラ ツール ウィンドウに表示されます。まだ中身は空なので、テーブルを追加しましょう。
a. データベースを展開し、[テーブル] を右クリックし、[テーブルの作成] を選択します。
b. 表示されたダイアログ ボックスで、テーブルの名前を指定し (私は "Books" という名前にしました)、列情報を追加します。私は次のようにしました。
i. “ISBN” – nvarchar 16, primary key. (プライマリ キーは、レコードを一意に識別するものと考えてください。ISBN 番号は一意ですが、題名や作者名は一意ではありません。)
ii. Title – nvarchar 128.
iii. Full Title – nvarchar 256.
iv. Author – nvarchar 128.
v. Publisher – nvarchar 128.
vi. Owned – int, no nulls allowed. (このフィールドは、その本を既に購入したかどうかを示します。コードではブール型として扱います。)
これでデータベースの完成です。レコードはまだ入っていませんが、後で入れます。
データベースを使用する
データベースは Visual Studio で認識されるようになりましたが、まだ実際には使用していません。まず Windows アプリケーションを作成することから始めましょう。私が作成するアプリケーションは "VBLibrary" という名前にしました。ソリューション エクスプローラの近くに [データ ソース] というツール ウィンドウが表示されます。このウィンドウが見つからない場合は、[データ]、[データ ソースの表示] の順に選択すると表示されます。このツール ウィンドウの中央に [新しいデータ ソースの追加] というリンクがあるので、それをクリックします (このコマンドは [データ] メニューから実行することもできます)。
データ ソースの追加ウィザードが起動します。これはとても使いやすいウィザードです。
1. 最初のページで、Database オブジェクトが選択されていることを確認したら、[次へ] をクリックします。
2. 2 番目のページでは、作成したデータベースがドロップダウン リストで選択されていることを確認し、[次へ] をクリックします。必要に応じて、プロジェクトにデータベース ファイルを追加するように求めるメッセージが表示されます。私の場合は、プロジェクトでデータベースを配布する必要がないのと、コンピュータ上に 1 つのコピーだけを置いておきたいので、[いいえ] を選択しました。
3. 最後のページで [完了] をクリックします。
これで、[データ ソース] ウィンドウにテーブルが表示されます。フォームにデータを配置するのは簡単で、テーブルをフォームにドラッグするだけです。ただし、それを行う前に、ちょっとした調整もできます。私は、既定のデータ グリッドではなく標準的なコントロール UI が好きなので、ちょっと調整しました。まず [Books] を選択し、その横に表示されるドロップダウン リストをクリックし、[詳細] を選択します。これで、[Books] のアイコンがフォームっぽいアイコンに変わります。次に、[Books] を右クリックし、[データセット デザイナで編集する] を選択します。これで、データ デザイナが開き、テーブルが表示されます。アプリケーションでデータを実際に使用する方法を、ここでカスタマイズできます。
1. テーブル内で [Title] を選択し、プロパティ グリッドで [NullValue] を [(Empty)] に変更します。これは、データが存在しない場合に、例外をスローせずに Title を空の文字列として扱うためです。この作業を [Full Title]、[Author]、および [Publisher] についても繰り返します。私がこうしたのは、これらのフィールドに値が入力されていてもいなくてもかまわないからです。
2. テーブル内で [Owned] を選択し、プロパティ グリッドで次のように変更します。
a. DataType を System.Boolean に変更します (このように変更すると、[データ ソース] ウィンドウに表示される [Owned] がチェック ボックスになります)。
b. DefaultValue を True に変更します。データベースに作成するエントリの大部分は既に購入済みの本なので、これが既定値になります。
c. AllowDBNull を False に変更します。本は必ず、購入済み、または未購入になるので、ここでは Null 値は許可されません。
これで、データ デザイナでの作業は終わりです。[データ ソース] ウィンドウから [Books] テーブルをフォームにドラッグすると、すべてのデータ コントロールが設定され、各コントロールにバインディング コードが自動的に生成されます。ナビゲーション バーも自動的に生成されるので、レコードを作成したり、レコードにアクセスしたりするときに使用できます。
フォームをクリーンアップする
作成したコントロールは、他のコントロールと同じようにドラッグしたり調整したりできます。不要と判断したコントロールを削除することもできます。たとえば、私は [Checkbox1] の前の [Owned] ラベルを削除し、そのチェック ボックスのテキストを [Owned] に変更しました。私はチェック ボックスのラベルを使用しないのです。
ユーザーが簡単にデータを入力できるようにするには、各フィールドをクリックし、プロパティ グリッドで MaxLength プロパティの値をデータ値の長さに合わせて変更します。そうすることで、そのフィールドでデータベース内に保持できる以上のデータを誤って入力することがなくなります。コード ジェネレータでは、コントロールの作成時にこの処理を自動的には行いません。
私は、ユーザーが偽のレコードを保存することも防ぎたいと思います。この場合、ISBN 番号のないレコードは偽のレコードになります (テーブルの作成時に ISBN 番号を必須入力と定義しています)。そのため、フォームに次のコードを追加しました (フォームを右クリックし、[コードの表示] を選択)。
Private Sub ISBNTextBox_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles ISBNTextBox.TextChanged, BindingNavigatorAddNewItem.MouseUp
Dim enableButtons As Boolean = (ISBNTextBox.TextLength <> 0)
Me.BindingNavigatorAddNewItem.Enabled = enableButtons
Me.BindingNavigatorCountItem.Enabled = enableButtons
Me.BindingNavigatorMoveFirstItem.Enabled = enableButtons
Me.BindingNavigatorMoveNextItem.Enabled = enableButtons
Me.BindingNavigatorMovePreviousItem.Enabled = enableButtons
Me.BindingNavigatorPositionItem.Enabled = enableButtons
Me.BooksBindingNavigatorSaveItem.Enabled = enableButtons
End Sub
基本的にここでは、ISBN 値が空かどうかを確認し、空の場合は Delete 以外のビューア コントロールをすべて無効にします。空でない場合はすべて有効にします。Handles 句は、新しい (既定では空の) レコードが追加されるたびに、またはフィールドの値が変わるたびに、これを確認することを示しています。コントロールを無効にしない場合、ユーザーが未完成のレコードを保存しようとしたり、レコードが未完成のまま他のレコードに移動しようとしたりして、例外が発生する可能性があります。もちろん、例外を処理することもできますが、私はユーザーが最初からこの問題を回避できた方がよいと思います。
F5 キーを押すと、作成したアプリケーションが起動します。これで、プラス記号 (+) のように見えるボタンを使用してレコードを追加したり、レコードを保存したり、レコード間を移動したりできます。ツール バーの [Save] をクリックするとデータベースが更新されます。便利でしょう!
LINQ を使用する
このアプリケーションに小さな LINQ コードを含めるとお約束したので、LINQ を使ってレポートを生成しようと思います。興味はあるけれどまだ購入していない本の一覧を作成してファイルに保存すれば、ネット書店で本を探すときに使ったり、書店に行くときに印刷して持って行ったりできると考えたんです。
フォームにボタンを追加して「Generate Report」という名前を付けましょう。このボタンをダブルクリックすると、そのクリック ハンドラに移動します。最初にしなければならないのは、データベースで対象となる本をクエリすることです。
Dim unownedBooks = From book In GertzLibraryDataSet.Books _
Where book.Owned = False _
Select book.Author, book.Title
この行では 2 つの興味深い処理が行われます。まず、VB では (その場で) 自動的に、特定の型のオブジェクト ("匿名型") が作成されます。このオブジェクトには、2 つの文字列 (対応するデータベース値と同一の型情報を持つ、"Author" および "Title") を保持できます。また、Owned = False であるレコードだけを使用して、列挙可能なセットが作成されます。
これで、これらのオブジェクトを列挙し、人が解読できる形にすることができます。
Dim reportResults As New List(Of String)
Dim reportLine As String
For Each unownedBook In unownedBooks
reportLine = unownedBook.Author & ", """ & unownedBook.Title & """"
reportResults.Add(reportLine)
Next
このレポート情報をファイルに保存したいので、ファイル ダイアログ ボックスが必要になります。ツールボックスからフォームに SaveFileDialog オブジェクトをドラッグすると、下のトレイに表示され、他のウィンドウなしのコントロールも既に設定されています。これを選択し、プロパティ グリッドで次のような変更を加えます。
· NameàSaveReportDlg
· DefaultExtàtxt(これにより、ファイル名に必要に応じて拡張子 .txt が追加されます。)
· FileNameàMyReport (既定のファイル名になります。ユーザーがファイル名を変更することもできます。)
· Filterà Text files (*.txt)|*.txt (ダイアログ ボックスのファイルの種類のドロップダウン リストに値が設定されます。)
· TitleàSave Report (ダイアログ ボックスのタイトル バーに表示されます。)
ここでボタン ハンドラに戻り、次のコードを追加します。
If Me.SaveReportDlg.ShowDialog = Windows.Forms.DialogResult.OK Then
My.Computer.FileSystem.WriteAllText(Me.SaveReportDlg.FileName, _
“Books to Buy” & vbCrLf, False)
My.Computer.FileSystem.WriteAllText(Me.SaveReportDlg.FileName, _
"------------------" & vbCrLf, True)
For Each unownedBook In unownedBooks
My.Computer.FileSystem.WriteAllText(Me.SaveReportDlg.FileName, _
unownedBook.Author & ", """ & unownedBook.Title & """" & vbCrLf
Next
End If
終わりました! これで、F5 キーを押してレポート ボタンをクリックすると、次のように、レポートがディスクに保存されます。ここでは、これらの本をデータベースに登録したと仮定しています。
Books to Buy
------------------------------------------
Paul Vick, “The Visual Basic .NET Programming Language”
The Unicode Consortium, “The Unicode Standard, Version 5.0”
Matt Gertz, “The Novel I Will Really, Truly, Honestly Write One of These Days (I Mean It)”
他のアイディア
このプロジェクトを始めてから、ISBN 番号を指定すれば必要なすべての書籍データを入手できる Web サービスがあることを知りました。こうしたサービスを利用すれば、データ入力がもっと簡単になります。本の後ろに書かれている ISBN 番号を入力してボタンをクリックするだけで、他の情報が自動的に入力されるようにできるのです。次はこれを試してみて、成功したら詳細をご報告します。
次回をお楽しみに。
--Matt--*
投稿 : 2008 年 3 月 2 日 5:25 PM
分類 : LINQ/VB9、Matt Gertz、VB2008
VB チームの Web ログ - https://blogs.msdn.com/vbteam/archive/2008/03/02/keeping-track-of-books-using-vb-matt-gertz.aspx (英語) より