Difference between revisions of "SQLdb Tutorial2/ja"

From Free Pascal wiki
Jump to navigationJump to search
 
(14 intermediate revisions by the same user not shown)
Line 5: Line 5:
 
== 概要 ==
 
== 概要 ==
  
If you have followed [[SQLdb Tutorial1]], you have a basic grid showing database information.
+
[[SQLdb Tutorial1/ja]]が済んでいるなら、データベースを表示する基本的なグリッドがあるはずだ
While this application works, we can add some refinements on this.
+
このアプリケーションが機能するためには若干の改良を加えることができる。
 
 
 
=== 動的データベース接続 ===
 
=== 動的データベース接続 ===
  
Line 13: Line 12:
 
前述したように、「実際の」アプリケーションでは通常、ユーザーが独自のユーザー名とパスワードを指定できる。
 
前述したように、「実際の」アプリケーションでは通常、ユーザーが独自のユーザー名とパスワードを指定できる。
  
それらを指定できるようにフォームを変更しよう。標準メニューから 2 つの [[TEdit]] を追加します。 名前のプロパティを「ユーザー名」と「パスワード」に設定する。
+
それらを指定できるようにフォームを変更しよう。標準メニューから 2 つの [[TEdit]] を追加する。 名前のプロパティを「ユーザー名」と「パスワード」に設定する。
 
肩越しに覗き見されることに対するセキュリティを確保するには、パスワードの PasswordChar プロパティを * (アスタリスク) に設定する。
 
肩越しに覗き見されることに対するセキュリティを確保するには、パスワードの PasswordChar プロパティを * (アスタリスク) に設定する。
  
Line 201: Line 200:
 
例えば。 SQLite と FPC 2.6.1 以前の PostgreSQL ドライバーには特殊な E*DatabaseError がなく、EDatabaseError を使用する必要がある。 FPC (開発版)の PostgreSQL に EPQDatabaseError がある。
 
例えば。 SQLite と FPC 2.6.1 以前の PostgreSQL ドライバーには特殊な E*DatabaseError がなく、EDatabaseError を使用する必要がある。 FPC (開発版)の PostgreSQL に EPQDatabaseError がある。
  
== Editing data using the grid ==
+
== グリッドを使用したデータの編集 ==
  
=== Editing ===
+
=== 編集 ===
  
Up to now, if you tried to edit data in the grid, the changes would not be saved. This is because the ''SQLQuery1'' is not instructed to send the changes to the database transaction at the right moment.
+
これまで、グリッド内のデータを編集しようとしても、変更は保存されなかった。 これは、「SQLQuery1」が適切なタイミングでデータベース トランザクションに変更を送信するように指示されていないためだ。
We need to fix this, and then commit the transaction in the database, so all changes get written. For this, you would use code like this:
+
これを修正し、データベースにトランザクションをコミットして、すべての変更が書き込まれるようにする必要がある。 このためには、次のようなコードを使用する。
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
SQLQuery1.ApplyUpdates; //Pass user-generated changes back to database...
+
SQLQuery1.ApplyUpdates; // ユーザーが生成した変更をデータベースに渡す...
SQLTransaction1.Commit; //... and commit them using the transaction.
+
SQLTransaction1.cmmit; //...そしてトランザクションを使用してコミットする。
//SQLTransaction1.Active now is false
+
//SQLTransaction1.Active false  
 
</syntaxhighlight>
 
</syntaxhighlight>
  
We want to make sure any edits (inserts, updates, deletes) are written to the database:
+
編集 (挿入、更新、削除) がデータベースに書き込まれることを確認したいとする。
  
* when the users changes the filtering criteria and presses the button to query the database
+
* ユーザーがフィルタリング基準を変更し、ボタンを押してデータベースにクエリを実行したとき
* when the form is closed
+
* フォームを閉じたとき
  
It makes sense to make a separate procedure for this that is called in those two instances.
+
これら 2 つのインスタンスで呼び出される、このために別のプロシージャを作成することは理にかなっている
Go to the code, and add an empty line here:
+
コードに移動し、ここに空の行を追加する。
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
  TForm1 = class(TForm)
+
TForm1 = class(TForm)
 
     Button1: TButton;
 
     Button1: TButton;
 
     Datasource1: TDatasource;
 
     Datasource1: TDatasource;
Line 231: Line 230:
 
     SQLQuery1: TSQLQuery;
 
     SQLQuery1: TSQLQuery;
 
     SQLTransaction1: TSQLTransaction;
 
     SQLTransaction1: TSQLTransaction;
*****insert the empty line here****
+
*****ここに空行を挿入****
 
     procedure Button1click(Sender: TObject);
 
     procedure Button1click(Sender: TObject);
 
     procedure Formclose(Sender: TObject; var Closeaction: Tcloseaction);
 
     procedure Formclose(Sender: TObject; var Closeaction: Tcloseaction);
Line 237: Line 236:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
then type:
+
次に、次のように入力する。
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
    procedure SaveChanges;
+
    procedure SaveChanges;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
press shift-ctrl-c (default combination) to let code completion automatically create the corresponding procedure body.
+
shift-ctrl-c (デフォルトの組み合わせ) を押すと、コード補完によって対応するプロシージャ本体が自動的に作成される。
  
We need to add error handling and check that the transaction is active - remember, this code also gets called when pressing the button the first time, when the transaction is not active yet. We get:
+
エラー処理を追加して、トランザクションがアクティブであることを確認する必要がある。このコードは、トランザクションがまだアクティブではないときに初めてボタンを押したときにも呼び出されることを覚えておくこと。ここで:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 253: Line 252:
 
   try
 
   try
 
     if SQLTransaction1.Active then
 
     if SQLTransaction1.Active then
     // Only if we are within a started transaction;
+
     // 開始されたトランザクション内にいる場合のみ;
     // otherwise you get "Operation cannot be performed on an inactive dataset"
+
     // それ以外の場合は、"Operation cannot be performed on an inactive dataset"というメッセージが表示される。
 
     begin
 
     begin
       SQLQuery1.ApplyUpdates; //Pass user-generated changes back to database...
+
       SQLQuery1.ApplyUpdates; // ユーザーが生成した変更をデータベースに渡す...
       SQLTransaction1.Commit; //... and commit them using the transaction.
+
       SQLTransaction1.Commit; //...そしてトランザクションを使用してコミットする。
       //SQLTransaction1.Active now is false
+
       //SQLTransaction1.Active false
 
     end;
 
     end;
 
   except
 
   except
Line 272: Line 271:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Now we need to call this procedure at the appropriate moments:
+
次に、適切な時点でこのプロシージャを呼び出す必要がある。
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
 
procedure Tform1.Button1click(Sender: TObject);
 
procedure Tform1.Button1click(Sender: TObject);
 
begin
 
begin
   SaveChanges; //Saves changes and commits transaction
+
   SaveChanges; //変更を保存しトランザクションをコミット
 
   try
 
   try
 
     SQLQuery1.Close;
 
     SQLQuery1.Close;
Line 283: Line 282:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
and:
+
そして:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
 
procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);
 
procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);
 
begin
 
begin
   SaveChanges; //Saves changes and commits transaction
+
   SaveChanges; //変更を保存しトランザクションをコミット
 
   SQLQuery1.Close;
 
   SQLQuery1.Close;
 
....
 
....
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Now test and see if edits made in the dbgrid are saved to the database.
+
次に、dbgrid で行われた編集がデータベースに保存されるかどうかをテストして確認する。
  
=== Hiding primary key column ===
+
=== 主キー列の非表示 ===
  
Often, you don't want your users to see autonumber/generated primary keys as they are only meant to maintain referential integrity. If users do see them, they might want to try the edit the numbers, get upset that the numbers change, that there are gaps in the numbers, etc.
+
多くの場合、自動採番/生成された主キーは参照整合性を維持することのみを目的としているため、ユーザーに表示されたくないことがある。 ユーザーがそれらを見た場合、数値を編集しようとしたり、数値が変わったり、数値にギャップがあるなどのことに腹を立てたりする可能性がある。
  
In our example, CUST_NO is the primary key, with content auto-generated by Firebird using triggers and a sequence/generator. This means that you can insert a new record without specifying the CUST_NO; Firebird will create one automatically.
+
この例では、CUST_NO が主キーで、コンテンツはトリガーとシーケンス/ジェネレーターを使用して Firebird によって自動生成される。 これは、CUST_NO を指定せずに新しいレコードを挿入できることを意味する。Firebird が自動的に作成する。
  
We could simply change our SQLQuery1.SQL.Text property to not include CUST_NO, but this would lead to problems when editing data - a primary key is needed in those circumstances for uniquely identifying the row/record in question.
+
CUST_NO を含めないように SQLQuery1.SQL.Text プロパティを変更することもできますが、これによりデータ編集時に問題が発生する。このような状況では、問題の行/レコードを一意に識別するために主キーが必要になる。
  
Therefore, let's use a trick to query for all columns/fields in the table, but keep the grid from showing the first field, CUST_NO: in the Button1Click procedure, add code so it looks like:
+
したがって、テーブル内のすべての列/フィールドをクエリするトリックを使用するが、Button1Click プロシージャの最初のフィールド CUST_NO: がグリッドに表示されないようにして、次のようにコードを追加する:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 310: Line 309:
 
...
 
...
 
     SQLQuery1.Open;
 
     SQLQuery1.Open;
    // Hide the primary key column which is the first column in our queries.
+
    // クエリの最初の列である主キー列を非表示にする
    // We can only do this once the DBGrid has created the columns
+
    // DBGrid が列を作成した後でのみこれを行うことができる
 
     DBGrid1.Columns[0].Visible:=false;
 
     DBGrid1.Columns[0].Visible:=false;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Recompile, and check to see if the primary key column is really hidden.
 
  
==== SQLite, other databases ====
+
再コンパイルし、主キー列が本当に非表示になっているかどうかを確認する。
 +
 
 +
==== SQLite、その他のデータベース ====
  
* Other databases: a lot of other databases use an 'autonumber' or 'autoinc' type of field to provide auto-generated field content. Try changing your table definition and see if it works.
+
* その他のデータベース: 他の多くのデータベースは、自動生成されたフィールド コンテンツを提供するために「autonumber」または「autoinc」タイプのフィールドを使用します。 テーブル定義を変更して、それが機能するかどうかを確認すること。
* Sqlite: the example above works for SQLite as is because we're using an integer primary key. See the [http://www.sqlite.org/autoinc.html documentation] for details.
+
* Sqlite: 整数の主キーを使用しているため、上記の例は SQLite でそのまま機能します。 詳細については、[http://www.sqlite.org/autoinc.html ドキュメント] を参照のこと。
  
=== Inserting new data ===
+
=== 新しいデータの挿入 ===
  
If you insert new rows/records without any CUST_NO information you may have noticed that you get an error message: <tt>Field CUST_NO is required, but not supplied</tt>. This also happens if you hid the CUST_NO column, as in the previous section.
+
CUST_NO 情報なしで新しい行/レコードを挿入すると、次のエラー メッセージが表示されることに気づいたかもしれない: <tt>Field CUST_NO is required, but not supplied</tt>。 これは、前のセクションのように CUST_NO 列を非表示にした場合にも発生する。
  
The reason: Lazarus thinks that CUST_NO is required. That's not so strange, because it is a primary key and the underlying table definition in the database does say it is required.
+
理由: Lazarus CUST_NO が必要であると考えている。 これはそれほど奇妙ではない。これは主キーであり、データベース内の基になるテーブル定義で必須であると示されているからである。
  
If we can instruct Lazarus that this field is not actually required, we can pass empty values (=NULL values) to the database.
+
このフィールドが実際には必要ないことを Lazarus に指示できれば、空の値 (=NULL ) をデータベースに渡すことができる。
Fortunately, a query's field object has a ''Required'' property that does exactly that.
+
幸いなことに、クエリのフィールド オブジェクトには、まさにそれを行う ''Required'' プロパティがある。
  
Change the code to something like:
+
コードを次のように変更する。
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
    SQLQuery1.Open;
+
    SQLQuery1.Open;
    {
+
    {
    Make sure we don't get problems with inserting blank (=NULL) CUST_NO values, e.g.:
+
    空白 (=NULL) CUST_NO 値を挿入しても問題が発生しないことを確認のこと。例:
    Field CUST_NO is required, but not supplied
+
    フィールド CUST_NO は必須だが、指定されていない
    We need to tell Lazarus that, while CUST_NO is a primary key, it is not required
+
    Lazarus に、CUST_NO は主キーではあるが、新しいレコードを挿入するとき
    when inserting new records.
+
    必須ではないことを伝える必要がある。
    }
+
    }
    SQLQuery1.FieldByName('CUST_NO').Required:=false;
+
    SQLQuery1.FieldByName('CUST_NO').Required:=false;
    // Hide the primary key column which is the first column in our queries.
+
    // クエリの最初の列である主キー列を非表示にする。
    // We can only do this once the DBGrid has created the columns
+
    // DBGrid が列を作成した後でのみこれを行うことができる
    DBGrid1.Columns[0].Visible:=false;
+
    DBGrid1.Columns[0].Visible:=false;
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Deleting data ===
+
=== データを削除する ===
  
You can let your users use the mouse to do this. You don't even need to code a single line for this functionality...
+
ユーザーにマウスを使用してこれを実行させることができる。 この機能については 1 行もコーディングする必要はない。
  
On the 'Data Controls' tab, select a ''TDBNavigator'' component and drop it on the form, above the grid.
+
「データ コントロール」タブで、「TDBNavigator」コンポーネントを選択し、フォームのグリッドの上にドロップする。
  
To indicate what the navigator should be linked to, set its ''DataSource'' property to your existing datasource ('DataSource1') using the Object Inspector.
+
ナビゲーターのリンク先を指定するには、オブジェクトインスペクタを使用して、ナビゲーターの ''DataSource'' プロパティを既存のデータソース ('DataSource1') に設定する。
Now you can use the button on the ''DBNavigator'' to delete records, but also insert them, and move around the records. Also, when editing cells/fields, you can use the ''Cancel'' button to cancel your edits.
+
これで、「DBNavigator」のボタンを使用してレコードを削除できるだけでなく、レコードを挿入したり、レコード内を移動したりすることもできる。 また、セル/フィールドを編集する場合、「キャンセル」ボタンを使用して編集をキャンセルすることができる。
  
To allow users to delete the row they're in on the grid using the {{keypress|Delete}} key, add ''LCLType'' (this contains definitions for key codes) to your uses clause:
+
ユーザーが {{keypress|Delete}} キーを使用してグリッド上の行を削除できるようにするには、uses 句に ''LCLType'' (これにはキー コードの定義が含まれる) を追加する。
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 364: Line 364:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
... then handle the KeyUp event for the grid, which occurs when a key is released if in the grid. However, we do need to check that the user is not editing a field - as he'll probably use the {{keypress|Delete}} key to delete letters rather than the record he's working on.
+
... 次に、グリッドの KeyUp イベントを処理する。このイベントは、グリッド内にある場合にキーが放されたときに発生する。 ただし、ユーザーがフィールドを編集していないことを確認する必要がある。ユーザーは、作業中のレコードではなく文字を削除するために {{keypress|Delete}} キーを使用する可能性が高いためである。
  
Select the grid, then go to events and create an OnKeyUp event like this:
+
グリッドを選択し、イベントに移動して次のように OnKeyUp イベントを作成する。
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 372: Line 372:
 
   );
 
   );
 
begin
 
begin
   // Check for del key being hit and delete the current record in response
+
   // del キーが押されたことを確認し、データを編集していない限り
   // as long as we're not editing data
+
   // それに応じて現在のレコードを削除する
 
   if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then
 
   if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then
 
   begin
 
   begin
     //... delete current record and apply updates to db:
+
     //... 現在のレコードを削除し、データベースに更新を適用する:
 
     SQLQuery1.Delete;
 
     SQLQuery1.Delete;
 
     SQLQuery1.ApplyUpdates;
 
     SQLQuery1.ApplyUpdates;
Line 383: Line 383:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
{{Note| By default TDBGrid property Options / dgDisableDelete is set to false, this means a user can delete any record with the {{keypress|ctrl}}-{{keypress|delete}} key combo. You may not want this behaviour.}}
+
{{Note| デフォルトでは、TDBGrid プロパティ Options / dgDisableDelete false に設定されている。これは、ユーザーが {{keypress|ctrl}}-{{keypress|delete}} キーの組み合わせを使用して任意のレコードを削除できることを意味する。 この動作は望ましくないかもしれない。}}
  
== Summary ==
+
== 要約 ==
  
If you followed along up to now, you can retrieve data from the database, filter it, and edit and delete data in the grid. Your code should look something like this:
+
ここまで手順を進めてきたら、データベースからデータを取得し、フィルタリングし、グリッド内のデータを編集および削除できる。 コードは次のようになる:
  
 
<syntaxhighlight lang=pascal>
 
<syntaxhighlight lang=pascal>
Line 440: Line 440:
  
 
procedure Tform1.Savechanges;
 
procedure Tform1.Savechanges;
// Saves edits done by user, if any.
+
// もしあれば、ユーザーによる編集を保存する。Saves edits done by user, if any.
 
begin
 
begin
 
   try
 
   try
 
     if SQLTransaction1.Active then
 
     if SQLTransaction1.Active then
     // Only if we are within a started transaction
+
     // トランザクションを開始したときのみ
     // otherwise you get "Operation cannot be performed on an inactive dataset"
+
     // さもないと"Operation cannot be performed on an inactive dataset"にであることになる。
 
     begin
 
     begin
       SQLQuery1.ApplyUpdates; //Pass user-generated changes back to database...
+
       SQLQuery1.ApplyUpdates; //ユーザーによる変更をデータベースに戻すPass user-generated changes back to database...
       SQLTransaction1.Commit; //... and commit them using the transaction.
+
       SQLTransaction1.Commit; //... トランザクションを用いてコミット
 
       //SQLTransaction1.Active now is false
 
       //SQLTransaction1.Active now is false
 
     end;
 
     end;
Line 465: Line 465:
 
   );
 
   );
 
begin
 
begin
   // Check for del key being hit and delete the current record in response
+
   // データを編集しているとき以外に
   // as long as we're not editing data
+
   // Delキーが押され、それに応じて現在のレコードを消去する。
 
   if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then
 
   if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then
 
   begin
 
   begin
Line 477: Line 477:
 
procedure Tform1.Button1click(Sender: TObject);
 
procedure Tform1.Button1click(Sender: TObject);
 
begin
 
begin
   SaveChanges; //Saves changes and commits transaction
+
   SaveChanges; //変更を保存し、トランザクションをコミット
 
   try
 
   try
 
     SQLQuery1.Close;
 
     SQLQuery1.Close;
     //Connection settings for Firebird/Interbase database
+
     //Firebird/Interbaseデータベースの接続設定
     //only needed when we have not yet connected:
+
     //まだ、接続していないときにのみ必要である:
 
     if not DBConnection.Connected then
 
     if not DBConnection.Connected then
 
     begin
 
     begin
Line 488: Line 488:
 
       DBConnection.Username := UserName.Text;
 
       DBConnection.Username := UserName.Text;
 
       DBConnection.Password := Password.Text;
 
       DBConnection.Password := Password.Text;
       // Now we've set up our connection, visually show that
+
       // コネクションを張り、
       // changes are not possibly any more
+
       // 変更はもうないと視覚的に訴える
 
       ServerName.ReadOnly:=true;
 
       ServerName.ReadOnly:=true;
 
       DatabaseName.ReadOnly:=true;
 
       DatabaseName.ReadOnly:=true;
Line 495: Line 495:
 
       Password.ReadOnly:=true;
 
       Password.ReadOnly:=true;
 
     end;
 
     end;
     // Show all records, or filter if user specified a filter criterium
+
     // すべてのレコードもしくはユーザーによって定義されたフィルタ定義で表示
 
     if Edit1.Text='' then
 
     if Edit1.Text='' then
 
       SQLQuery1.SQL.Text := 'select * from CUSTOMER'
 
       SQLQuery1.SQL.Text := 'select * from CUSTOMER'
Line 507: Line 507:
 
     SQLQuery1.Open;
 
     SQLQuery1.Open;
 
     {
 
     {
     Make sure we don't get problems with inserting blank (=NULL) CUST_NO values, i.e. error message:
+
     (=NULL)値を挿入しても問題ない、即ち、エラーメッセージ "Field CUST_NO is required, but not supplied"
    "Field CUST_NO is required, but not supplied"
+
     が現れないようにすること。CUST_NOがプライマリキーであるときLazarusにそれを教える必要がある
     We need to tell Lazarus that, while CUST_NO is a primary key, it is not required
+
     新しいレコードが挿入されるときには必要ない
     when inserting new records.
 
 
     }
 
     }
 
     SQLQuery1.FieldByName('CUST_NO').Required:=false;
 
     SQLQuery1.FieldByName('CUST_NO').Required:=false;
 
     {
 
     {
     Hide the primary key column which is the first column in our queries.
+
     クエリの最初のカラムであるプライマリキーを隠す。
     We can only do this once the DBGrid has created the columns
+
     これはDBGridがカラムを生成するときに一度だけ行える
 
     }
 
     }
 
     DBGrid1.Columns[0].Visible:=false;
 
     DBGrid1.Columns[0].Visible:=false;
 
   except
 
   except
     // EDatabaseError is a general error;  
+
     // EDatabaseErrorは一般的なエラーだ;  
     // you could also use one for your specific db, e.g.
+
     // 例えば、Firebird/Interbaseにおいては、EIBDatabaseErrorのような
     // use EIBDatabaseError for Firebird/Interbase
+
     // データベースに特異なものを用いたほうがいいかもしれない
 
     on E: EDatabaseError do
 
     on E: EDatabaseError do
 
     begin
 
     begin
Line 533: Line 532:
 
procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);
 
procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);
 
begin
 
begin
   SaveChanges; //Saves changes and commits transaction
+
   SaveChanges; //変更を保存し、トランザクションをコミットする
 
   SQLQuery1.Close;
 
   SQLQuery1.Close;
 
   SQLTransaction1.Active := False;
 
   SQLTransaction1.Active := False;
Line 542: Line 541:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== Embedded database without code changes ==
+
== コード変更のない組み込みデータベース ==
 
+
===Windows 上のFirebird ===
=== Firebird on Windows ===
+
Windows の Firebird ユーザーへのボーナス: このチュートリアルに従っている場合は (基本的な例しか実行していない場合でも)、埋め込まれた Firebird ライブラリの fbembed.dll の名前が fbclient.dll に変更されている。 これにより、Lazarus は通常の Firebird サーバ (別のマシンまたはローカルマシンのいずれか) に接続できるようになる。 ただし、サーバをセットアップせずに、employee.fdb データベースをアプリケーション ディレクトリにコピーし、アプリケーションを実行し、サーバ名 TEdit をクリアして、埋め込まれた Firebird を使用してデータベース ファイルに直接接続することもできる。
 
 
A bonus for Firebird users on Windows: if you have been following this tutorial (even if you only did the basic example), you renamed the <tt>fbembed.dll</tt> embedded Firebird library to <tt>fbclient.dll</tt>. With this, Lazarus could connect to regular Firebird servers (either on another machine or on your local machine).
 
However, you can also copy the <tt>employee.fdb</tt> database to your application directory, run the application, clear the ''Server name'' TEdit and use Firebird embedded to directly connect to the database file, without any servers set up.
 
  
This is great if you want to deploy database applications to end users, but don't want the hassle of installing servers (checking if a server is already installed, if it's the right version, having users check firewalls, etc).
+
これは、データベース アプリケーションをエンド ユーザーに展開したいが、サーバのインストールに手間をかけたくない (サーバがすでにインストールされているかどうか、バージョンが正しいかどうかを確認する、ユーザーにファイアウォールを確認させるなど) 場合に最適である。
  
See [[Firebird embedded]] for more details.
+
詳細については、[[Firebird embedded]] を参照されたい。
  
September 2011: in recent development (SVN) versions of Free Pascal, FPC tries to first load <tt>fbembed.dll</tt>, so you need not rename <tt>fbclient.dll</tt> anymore for this to work.
+
2011 年 9 月: Free Pascal の最近の開発 (SVN) バージョンでは、FPC は最初に fbembed.dll をロードするので、これが機能するために fbclient.dll の名前を変更する必要はなくなった。
  
=== Firebird on Linux/macOS/Unix ===
+
=== Linux/macOS/Unix 上の Firebird ===
 
+
これを Linux/macOS で動作させる方法があるはずだ。 ヒントとリンクについては、[[Firebird]]を参照されたい。 Wiki の更新は大歓迎である。
There must be a way to get this to work on Linux/macOS. See [[Firebird]] for hints and links. Updates to the wiki are welcome.
 
  
 
=== SQLite ===
 
=== SQLite ===
 +
SQLite は確かに組み込み機能を提供するが、その一方で、クライアント/サーバのセットアップは許可されていない。 上記のチュートリアルに従うと、データベース (SQLite と Firebird など) の切り替えがそれほど難しい作業ではないことがわかる。
  
SQLite certainly offers embedded functionality - it does not allow a client/server setup on the other hand.
+
その他のデータベース
By following the tutorial above, you can see that switching between databases (e.g. SQLite and Firebird) is not so much work at all.
+
データベースでも同様の機能が提供されている場合がある。 他のデータベース システム用のこの Wiki の更新も歓迎である。
 
 
=== Other databases ===
 
 
 
Your database might offer similar functionality. Updates of this wiki for other database systems are welcome.
 
 
 
== See also ==
 
  
* [[SQLdb Tutorial0]]: Instructions for setting up sample tables/sample data for the tutorial series.
+
== 関連情報 ==
* [[SQLdb Tutorial1]]: First part of the DB tutorial series, showing how to set up a grid that shows database data
+
* [[SQLdb Tutorial1/ja]]: DB チュートリアルの第一の部分。データベースのデータを、どのように grid に表示させるかを学びます。
* [[SQLdb Tutorial3]]: Third part of the DB tutorial series, showing how to program for multiple databases and use a login form
+
* [[SQLdb Tutorial2/ja]]: DB チュートリアルの第二の部分。データベースのデータの挿入や編集について学びます。
* [[SQLdb Tutorial4]]: Fourth part of the DB tutorial series, showing how to use data modules
+
* [[SQLdb Tutorial3/ja]]: DB チュートリアルの第三の部分。複数のデータベースについてのプログラムやログインフォームの使い方を学びます。
* [[Lazarus Database Overview]]: Information about the databases that Lazarus supports. Links to database-specific notes.
+
* [[SQLdb Tutorial4/ja]]: DB チュートリアルの第四の部分。どのようにデータモジュールを用いるかを学びます。
* [[SQLdb Package]]: information about the SQLdb package
+
* [[Lazarus Database Overview/ja]]: Lazarus がサポートしているデータベースについての情報。 データベースごとの記述へのリンクを含みます。
* [[SQLdb Programming Reference]]: an overview of the interaction of the SQLdb database components
+
* [[SQLdb Package/ja]]: SQLdb パッケージについての情報
* [[SqlDBHowto]]: information about using the SQLdb package
+
* [[SQLdb Programming Reference/ja]]: SQLdb データベースコンポーネントの入出力の概要
* [[Working With TSQLQuery]]: information about TSQLQuery
+
* [[SqlDBHowto/ja]]: SQLdb パッケージを用いることについての情報
 +
* [[Working With TSQLQuery/ja]]: TSQLQuery についての情報

Latest revision as of 13:43, 29 March 2024

English (en) français (fr) 日本語 (ja)

データベースのポータル

参照:

チュートリアル/練習となる記事:

各種データベース

Advantage - MySQL - MSSQL - Postgres - Interbase - Firebird - Oracle - ODBC - Paradox - SQLite - dBASE - MS Access - Zeos

概要

SQLdb Tutorial1/jaが済んでいるなら、データベースを表示する基本的なグリッドがあるはずだ このアプリケーションが機能するためには若干の改良を加えることができる。

動的データベース接続

これまでは、わかりやすくするために、固定のデータベース サーバー名、データベースの場所、ユーザー名、パスワードを使用してきた。 前述したように、「実際の」アプリケーションでは通常、ユーザーが独自のユーザー名とパスワードを指定できる。

それらを指定できるようにフォームを変更しよう。標準メニューから 2 つの TEdit を追加する。 名前のプロパティを「ユーザー名」と「パスワード」に設定する。 肩越しに覗き見されることに対するセキュリティを確保するには、パスワードの PasswordChar プロパティを * (アスタリスク) に設定する。

接続を簡単にしたい場合 (もちろん安全性は低くなるが)、UserName Text プロパティを SYSDBA などの有効なデータベース ユーザーに設定できる。 パスワード テキスト プロパティをマスターキーのようなデフォルト値に設定することもでき、セキュリティが重要でない場合は開発者のマシンで簡単にテストできるが...

見た目上、ラベルを追加して何を入力すればよいのかわかるようにすると便利だ。

また、Firebird/Interbase サーバー上の従業員サンプル データベースに簡単に接続できるように、サーバー名とデータベース パス用の 2 つのテキスト ボックスを追加する。 さらに 2 つの TEdit を追加し、ServerName と DatabaseName という名前を付ける。

必要に応じて、「Text」プロパティを状況に応じたデフォルトの適切な値に設定できる。 localhost と C:\Program Files\Firebird\Firebird_2_5\examples\empbuild\EMPLOYEE.FDB

ユーザーが入力する必要がある内容を説明するラベルもここで役に立つ。

明確にするために、設計時コンポーネントから接続情報を削除する。TSQLConnector コンポーネントで、UserName、Password、DatabaseName、および HostName プロパティからすべてのテキストを削除する。

さて、最後に、データベース接続コンポーネントに接続方法を指示する必要がある。 これは通常、アプリケーションの実行の開始時にのみ必要になる。 この例では、既存の「Button1」コードが接続をセットアップする良い方法である。

以下が得られるまでコードを追加。

procedure TForm1.Button1Click(Sender: TObject);
begin
   SQLQuery1.Close;
   //Firebird/Interbaseデータベースの接続設定
   // まだ接続していない場合にのみ必要:
   if not DBConnection.Connected then
   begin
     DBConnection.HostName := ServerName.Text;
     DBConnection.データベース名 := データベース名.テキスト;
     DBConnection.DatabaseName := DatabaseName.Text;
     DBConnection.Password := Password.Text;
     // これで接続が設定された。それを視覚的に示す。
     // 変更はもう行われない可能性がある
    ServerName.ReadOnly:=true;
    DatabaseName.ReadOnly:=true;
    UserName.ReadOnly:=true;
    Password.ReadOnly:=true;
   end;
   SQLQuery1.SQL.Text:= 'select * from CUSTOMER';
   DBConnection.Connected:= True;
   SQLTransaction1.Active:= True;
   SQLQuery1.Open;
end;

次に、実行して接続できるかどうかをテストする。

SQLite、その他のデータベース

必要に応じて、例えば SQLite の employee.sqlite、DatabaseName TEdit の Text、 プロパティを調整する。 。

sqlite の場合、HostName、Username、および Password の指定は意味がないため、これらの TEdit を省略できる。 明らかに、上記のコードでは、対応する値を DBConnection に割り当てるのを省略またはコメントアウトする。 Firebird が埋め込まれている場合は、ユーザー名を SYSDBA にハードコーディングする。 sqlite を使用するときにはこれを指定しても問題ない。

コードは次のようになる:

procedure TForm1.Button1Click(Sender: TObject);
begin
   SQLQuery1.Close;
   //組み込みデータベースの接続設定
   // まだ接続していない場合にのみ必要:
   if not DBConnection.Connected then
   begin
      DBConnection.DatabaseName := DatabaseName.Text;
      DBConnection.UserName := 'SYSDBA';  //Firebird 埋め込みにはこれが必要。 SQLiteを使用する場合は問題ない
     // これで接続が設定された。それを視覚的に示す。
     // 変更はもう行われない可能性がある
      DatabaseName.ReadOnly:=true;
   end;
   SQLQuery1.SQL.Text:= 'select * from CUSTOMER';
   DBConnection.Connected:= True;
   SQLTransaction1.Active:= True;
   SQLQuery1.Open;
end;

データのフィルタリング

多くの場合、テーブルにはユーザーが見たくない大量のデータが含まれている (データベースからクエリを実行し、ネットワーク上を移動するには時間がかかる可能性がある)。米国からの顧客のみを表示する必要があると仮定する。 したがって、「SQLQuery1」の SQL 命令は次のようになる。

select * from CUSTOMER where COUNTRY = 'USA'

...これは、コードでは次のように変換される。

SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = 'USA'';

このサンプル アプリケーションでこの命令を使用しない理由は 2 つある。

まず、単一引用符の使用法に問題がある。 コンパイラーは USA の前の引用符を終了引用符 (最初の引用符は select from... の前にある) として解釈するため、SQL 命令は無効になる。 解決策: 内側の引用符を 2 倍にする。

SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = ''USA''';

2 番目の、より重要な理由は、ユーザーがどのような制約でフィルターをかけたいのかがおそらくわからないという事実だ。 ユーザーの柔軟性を制限したくはない。

この柔軟性を実現するには、まず SQL クエリ ステートメントを変更し、「USA」をプレースホルダー (SQL のパラメータ) に置き換える。Button1click プロシージャを変更して次のように置き換える。

SQLQuery1.SQL.Text := 'select * from CUSTOMER';

と:

SQLQuery1.SQL.Text:= 'select * from CUSTOMER where COUNTRY = :COUNTRY';

FPC SQLDB では、SQL パラメーターは先頭のコロンでマークされる (他の言語/環境では ? などの他の規則が使用されます)。 ユーザーがフィルターの値を入力できるようにするために、フォームに TEdit コンポーネントを配置する。 「Text」プロパティの値を削除する。

これで、TEdit に入力されたテキストを取得し、TSQLQuery の 'Params' プロパティを使用して SQL COUNTRY パラメータを入力できるようになった。 これを前のステートメントの下に追加する。

SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;

パラメータは位置または名前で指定できます。 名前を使用すると、ソース コードの読みやすさが向上し、既存のパラメーターの途中にさらにパラメーターを挿入する場合に明らかに役立つ。

.AsString を使用して文字列値をパラメータに割り当てる。 整数パラメータ、ブール値パラメータなどに対して同等のプロパティ割り当てがある。

これまでのコードでは、フィルターの使用を強制されている。 ユーザーが編集ボックスに空の値を指定した場合、レコードは表示されない。 おそらくこれは私たちが望んでいることではない。 空の値をテストし、それに応じてクエリを作成しよう。 最終的には次のような手順になるはずだ。

procedure TForm1.Button1Click(Sender: TObject);
begin
   SQLQuery1.Close;
   // Firebird/Interbaseデータベースの接続設定
   // まだ接続していない場合にのみ必要:
  if not DBConnection.Connected then
   begin
    DBConnection.HostName := ServerName.Text;
    DBConnection.DatabaseName := DatabaseName.Text;
    DBConnection.Username := UserName.Text;
    DBConnection.Password := Password.Text;
     // これで接続が設定された。それを視覚的に示す。
     // 変更はもう行われない可能性がある
    ServerName.ReadOnly:=true;
    DatabaseName.ReadOnly:=true;
    UserName.ReadOnly:=true;
    Password.ReadOnly:=true;
   end;
     // すべてのレコードを表示するか、ユーザーがフィルター基準を指定した場合はフィルターする
    if Edit1.Text='' then
     SQLQuery1.SQL.Text :=  'select * from CUSTOMER where COUNTRY = :COUNTRY';
    else
     begin
      SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = :COUNTRY';
      SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
    end;
   DBConnection.Connected:= True;
   SQLTransaction1.Active:= True;
   SQLQuery1.Open;
end;

ここで、Edit1 を使用してフィルタリングを少し試す。 データベースに存在しない国を入力すると、空のグリッドが表示される。

エラー処理

アプリケーションは実行されるはずだが、場合によっては問題が発生する可能性がある。 データベース、さらには組み込みデータベースもクラッシュする可能性があり (データベース サーバーがクラッシュした場合、ディスクがいっぱいになった場合、または単にバグが原因である場合など)、アプリケーションがハングしたままになる。

したがって、データベース (実際には任意の外部プロセス) へのアクセスは、「常に」、try ... 例外および/または try ...finally 構造に統合される必要がある。 これにより、データベース エラーが確実に処理され、ユーザーが孤立することがなくなる。 このサンプル アプリケーションの基本的なルーチンは次のようになる。

begin
   try
     SQLQuery1.Close;
     ...
     SQLQuery1.Open;
   except
     //一般的なデータベース エラーである EDatabaseErrorが必要だが、ここでは Firebird/Interbase を扱っているため、次のようになる:
      on E: EDatabaseError do
     begin
       MessageDlg('Error','A database error has occurred. Technical error message: ' + E.Message,mtError,[mbOK],0);
       Edit1.Text:='';
     end;
   end;
end;

SQLite、PostgreSQL、その他のデータベース

さらに詳細が必要な場合は、より汎用的な EDatabaseError を使用するか、使用可能な場合は独自の特殊な DatabaseError を使用できる。 例えば。 SQLite と FPC 2.6.1 以前の PostgreSQL ドライバーには特殊な E*DatabaseError がなく、EDatabaseError を使用する必要がある。 FPC (開発版)の PostgreSQL に EPQDatabaseError がある。

グリッドを使用したデータの編集

編集

これまで、グリッド内のデータを編集しようとしても、変更は保存されなかった。 これは、「SQLQuery1」が適切なタイミングでデータベース トランザクションに変更を送信するように指示されていないためだ。 これを修正し、データベースにトランザクションをコミットして、すべての変更が書き込まれるようにする必要がある。 このためには、次のようなコードを使用する。

SQLQuery1.ApplyUpdates; // ユーザーが生成した変更をデータベースに渡す...
SQLTransaction1.cmmit; //...そしてトランザクションを使用してコミットする。
//SQLTransaction1.Active は false

編集 (挿入、更新、削除) がデータベースに書き込まれることを確認したいとする。

  • ユーザーがフィルタリング基準を変更し、ボタンを押してデータベースにクエリを実行したとき
  • フォームを閉じたとき

これら 2 つのインスタンスで呼び出される、このために別のプロシージャを作成することは理にかなっている コードに移動し、ここに空の行を追加する。

TForm1 = class(TForm)
    Button1: TButton;
    Datasource1: TDatasource;
    DBGrid1: TDBGrid;
    Edit1: TEdit;
    DBConnection: TIBConnection;
    SQLQuery1: TSQLQuery;
    SQLTransaction1: TSQLTransaction;
*****ここに空行を挿入****
    procedure Button1click(Sender: TObject);
    procedure Formclose(Sender: TObject; var Closeaction: Tcloseaction);
  private

次に、次のように入力する。

     procedure SaveChanges;

shift-ctrl-c (デフォルトの組み合わせ) を押すと、コード補完によって対応するプロシージャ本体が自動的に作成される。

エラー処理を追加して、トランザクションがアクティブであることを確認する必要がある。このコードは、トランザクションがまだアクティブではないときに初めてボタンを押したときにも呼び出されることを覚えておくこと。ここで:

procedure Tform1.SaveChanges;
// Saves edits done by user, if any.
begin
  try
    if SQLTransaction1.Active then
    // 開始されたトランザクション内にいる場合のみ;
    // それ以外の場合は、"Operation cannot be performed on an inactive dataset"というメッセージが表示される。
    begin
      SQLQuery1.ApplyUpdates; // ユーザーが生成した変更をデータベースに渡す...
      SQLTransaction1.Commit; //...そしてトランザクションを使用してコミットする。
      //SQLTransaction1.Active は false
    end;
  except
  on E: EDatabaseError do
    begin
      SQLTransaction1.Rollback;
      MessageDlg('Error', 'A database error has occurred. Technical error message: ' +
        E.Message, mtError, [mbOK], 0);
      Edit1.Text := '';
    end;
  end;
end;

次に、適切な時点でこのプロシージャを呼び出す必要がある。

procedure Tform1.Button1click(Sender: TObject);
begin
  SaveChanges; //変更を保存しトランザクションをコミット
  try
    SQLQuery1.Close;
....

そして:

procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);
begin
  SaveChanges; //変更を保存しトランザクションをコミット
  SQLQuery1.Close;
....

次に、dbgrid で行われた編集がデータベースに保存されるかどうかをテストして確認する。

主キー列の非表示

多くの場合、自動採番/生成された主キーは参照整合性を維持することのみを目的としているため、ユーザーに表示されたくないことがある。 ユーザーがそれらを見た場合、数値を編集しようとしたり、数値が変わったり、数値にギャップがあるなどのことに腹を立てたりする可能性がある。

この例では、CUST_NO が主キーで、コンテンツはトリガーとシーケンス/ジェネレーターを使用して Firebird によって自動生成される。 これは、CUST_NO を指定せずに新しいレコードを挿入できることを意味する。Firebird が自動的に作成する。

CUST_NO を含めないように SQLQuery1.SQL.Text プロパティを変更することもできますが、これによりデータ編集時に問題が発生する。このような状況では、問題の行/レコードを一意に識別するために主キーが必要になる。

したがって、テーブル内のすべての列/フィールドをクエリするトリックを使用するが、Button1Click プロシージャの最初のフィールド CUST_NO: がグリッドに表示されないようにして、次のようにコードを追加する:

procedure Tform1.Button1click(Sender: TObject);
begin
...
    SQLQuery1.Open;
     // クエリの最初の列である主キー列を非表示にする
     // DBGrid が列を作成した後でのみこれを行うことができる
    DBGrid1.Columns[0].Visible:=false;


再コンパイルし、主キー列が本当に非表示になっているかどうかを確認する。

SQLite、その他のデータベース

  • その他のデータベース: 他の多くのデータベースは、自動生成されたフィールド コンテンツを提供するために「autonumber」または「autoinc」タイプのフィールドを使用します。 テーブル定義を変更して、それが機能するかどうかを確認すること。
  • Sqlite: 整数の主キーを使用しているため、上記の例は SQLite でそのまま機能します。 詳細については、ドキュメント を参照のこと。

新しいデータの挿入

CUST_NO 情報なしで新しい行/レコードを挿入すると、次のエラー メッセージが表示されることに気づいたかもしれない: Field CUST_NO is required, but not supplied。 これは、前のセクションのように CUST_NO 列を非表示にした場合にも発生する。

理由: Lazarus は CUST_NO が必要であると考えている。 これはそれほど奇妙ではない。これは主キーであり、データベース内の基になるテーブル定義で必須であると示されているからである。

このフィールドが実際には必要ないことを Lazarus に指示できれば、空の値 (=NULL 値) をデータベースに渡すことができる。 幸いなことに、クエリのフィールド オブジェクトには、まさにそれを行う Required プロパティがある。

コードを次のように変更する。

     SQLQuery1.Open;
     {
     空白 (=NULL) CUST_NO 値を挿入しても問題が発生しないことを確認のこと。例:
     フィールド CUST_NO は必須だが、指定されていない
     Lazarus に、CUST_NO は主キーではあるが、新しいレコードを挿入するとき
     必須ではないことを伝える必要がある。
     }
     SQLQuery1.FieldByName('CUST_NO').Required:=false;
     // クエリの最初の列である主キー列を非表示にする。
     // DBGrid が列を作成した後でのみこれを行うことができる
     DBGrid1.Columns[0].Visible:=false;

データを削除する

ユーザーにマウスを使用してこれを実行させることができる。 この機能については 1 行もコーディングする必要はない。

「データ コントロール」タブで、「TDBNavigator」コンポーネントを選択し、フォームのグリッドの上にドロップする。

ナビゲーターのリンク先を指定するには、オブジェクトインスペクタを使用して、ナビゲーターの DataSource プロパティを既存のデータソース ('DataSource1') に設定する。 これで、「DBNavigator」のボタンを使用してレコードを削除できるだけでなく、レコードを挿入したり、レコード内を移動したりすることもできる。 また、セル/フィールドを編集する場合、「キャンセル」ボタンを使用して編集をキャンセルすることができる。

ユーザーが Delete キーを使用してグリッド上の行を削除できるようにするには、uses 句に LCLType (これにはキー コードの定義が含まれる) を追加する。

uses
  Classes, SysUtils, sqldb, pqconnection, DB, FileUtil, Forms,
  Controls, Graphics, Dialogs, DBGrids, StdCtrls, DbCtrls, LCLType;

... 次に、グリッドの KeyUp イベントを処理する。このイベントは、グリッド内にある場合にキーが放されたときに発生する。 ただし、ユーザーがフィールドを編集していないことを確認する必要がある。ユーザーは、作業中のレコードではなく文字を削除するために Delete キーを使用する可能性が高いためである。

グリッドを選択し、イベントに移動して次のように OnKeyUp イベントを作成する。

procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState
  );
begin
  // del キーが押されたことを確認し、データを編集していない限り
  // それに応じて現在のレコードを削除する
  if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then
  begin
    //... 現在のレコードを削除し、データベースに更新を適用する:
    SQLQuery1.Delete;
    SQLQuery1.ApplyUpdates;
  end;
end;
Light bulb  Note: デフォルトでは、TDBGrid プロパティ Options / dgDisableDelete は false に設定されている。これは、ユーザーが ctrl-delete キーの組み合わせを使用して任意のレコードを削除できることを意味する。 この動作は望ましくないかもしれない。

要約

ここまで手順を進めてきたら、データベースからデータを取得し、フィルタリングし、グリッド内のデータを編集および削除できる。 コードは次のようになる:

unit sqldbtutorial1unit;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, sqldb, pqconnection, DB, FileUtil, Forms,
  Controls, Graphics, Dialogs, DBGrids, StdCtrls, DbCtrls, LCLType;
type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    DatabaseName: TEdit;
    Datasource1: TDatasource;
    DBGrid1: TDBGrid;
    Dbnavigator1: Tdbnavigator;
    Edit1: TEdit;
    Label2: Tlabel;
    Label3: Tlabel;
    Label4: Tlabel;
    Label5: Tlabel;
    Password: TEdit;
    UserName: TEdit;
    ServerName: TEdit;
    DBConnection: TIBConnection;
    Label1: TLabel;
    SQLQuery1: TSQLQuery;
    SQLTransaction1: TSQLTransaction;
    procedure SaveChanges;
    procedure Button1click(Sender: TObject);
    procedure Formclose(Sender: TObject; var Closeaction: Tcloseaction);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure Tform1.Savechanges;
// もしあれば、ユーザーによる編集を保存する。Saves edits done by user, if any.
begin
  try
    if SQLTransaction1.Active then
    // トランザクションを開始したときのみ
    // さもないと"Operation cannot be performed on an inactive dataset"にであることになる。
    begin
      SQLQuery1.ApplyUpdates; //ユーザーによる変更をデータベースに戻すPass user-generated changes back to database...
      SQLTransaction1.Commit; //... トランザクションを用いてコミット
      //SQLTransaction1.Active now is false
    end;
  except
  on E: EDatabaseError do
    begin
      SQLTransaction1.Rollback;
      MessageDlg('Error', 'A database error has occurred. Technical error message: ' +
        E.Message, mtError, [mbOK], 0);
      Edit1.Text := '';
    end;
  end;
end;

procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState
  );
begin
  // データを編集しているとき以外に
  // Delキーが押され、それに応じて現在のレコードを消去する。
  if (key=VK_DELETE) and (not(DBGrid1.EditorMode)) then
  begin
    //... delete current record and apply updates to db:
    SQLQuery1.Delete;
    SQLQuery1.ApplyUpdates;
  end;
end; 

procedure Tform1.Button1click(Sender: TObject);
begin
  SaveChanges; //変更を保存し、トランザクションをコミット
  try
    SQLQuery1.Close;
    //Firebird/Interbaseデータベースの接続設定
    //まだ、接続していないときにのみ必要である:
    if not DBConnection.Connected then
    begin
      DBConnection.HostName := ServerName.Text;
      DBConnection.DatabaseName := DatabaseName.Text;
      DBConnection.Username := UserName.Text;
      DBConnection.Password := Password.Text;
      // コネクションを張り、
      // 変更はもうないと視覚的に訴える
      ServerName.ReadOnly:=true;
      DatabaseName.ReadOnly:=true;
      UserName.ReadOnly:=true;
      Password.ReadOnly:=true;
    end;
    // すべてのレコードもしくはユーザーによって定義されたフィルタ定義で表示
    if Edit1.Text='' then
      SQLQuery1.SQL.Text := 'select * from CUSTOMER'
    else
    begin
      SQLQuery1.SQL.Text := 'select * from CUSTOMER where COUNTRY = :COUNTRY';
      SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
    end;
    DBConnection.Connected := True;
    SQLTransaction1.Active := True; //Starts a new transaction
    SQLQuery1.Open;
    {
    空(=NULL)値を挿入しても問題ない、即ち、エラーメッセージ "Field CUST_NO is required, but not supplied"
    が現れないようにすること。CUST_NOがプライマリキーであるときLazarusにそれを教える必要がある
    新しいレコードが挿入されるときには必要ない
    }
    SQLQuery1.FieldByName('CUST_NO').Required:=false;
    {
    クエリの最初のカラムであるプライマリキーを隠す。
    これはDBGridがカラムを生成するときに一度だけ行える
    }
    DBGrid1.Columns[0].Visible:=false;
  except
    // EDatabaseErrorは一般的なエラーだ; 
    // 例えば、Firebird/Interbaseにおいては、EIBDatabaseErrorのような
    // データベースに特異なものを用いたほうがいいかもしれない
    on E: EDatabaseError do
    begin
      MessageDlg('Error', 'A database error has occurred. Technical error message: ' +
        E.Message, mtError, [mbOK], 0);
      Edit1.Text := '';
    end;
  end;
end;

procedure Tform1.Formclose(Sender: TObject; var Closeaction: Tcloseaction);
begin
  SaveChanges; //変更を保存し、トランザクションをコミットする
  SQLQuery1.Close;
  SQLTransaction1.Active := False;
  DBConnection.Connected := False;
end;

end.

コード変更のない組み込みデータベース

Windows 上のFirebird

Windows の Firebird ユーザーへのボーナス: このチュートリアルに従っている場合は (基本的な例しか実行していない場合でも)、埋め込まれた Firebird ライブラリの fbembed.dll の名前が fbclient.dll に変更されている。 これにより、Lazarus は通常の Firebird サーバ (別のマシンまたはローカルマシンのいずれか) に接続できるようになる。 ただし、サーバをセットアップせずに、employee.fdb データベースをアプリケーション ディレクトリにコピーし、アプリケーションを実行し、サーバ名 TEdit をクリアして、埋め込まれた Firebird を使用してデータベース ファイルに直接接続することもできる。

これは、データベース アプリケーションをエンド ユーザーに展開したいが、サーバのインストールに手間をかけたくない (サーバがすでにインストールされているかどうか、バージョンが正しいかどうかを確認する、ユーザーにファイアウォールを確認させるなど) 場合に最適である。

詳細については、Firebird embedded を参照されたい。

2011 年 9 月: Free Pascal の最近の開発 (SVN) バージョンでは、FPC は最初に fbembed.dll をロードするので、これが機能するために fbclient.dll の名前を変更する必要はなくなった。

Linux/macOS/Unix 上の Firebird

これを Linux/macOS で動作させる方法があるはずだ。 ヒントとリンクについては、Firebirdを参照されたい。 Wiki の更新は大歓迎である。

SQLite

SQLite は確かに組み込み機能を提供するが、その一方で、クライアント/サーバのセットアップは許可されていない。 上記のチュートリアルに従うと、データベース (SQLite と Firebird など) の切り替えがそれほど難しい作業ではないことがわかる。

その他のデータベース データベースでも同様の機能が提供されている場合がある。 他のデータベース システム用のこの Wiki の更新も歓迎である。

関連情報

  • SQLdb Tutorial1/ja: DB チュートリアルの第一の部分。データベースのデータを、どのように grid に表示させるかを学びます。
  • SQLdb Tutorial2/ja: DB チュートリアルの第二の部分。データベースのデータの挿入や編集について学びます。
  • SQLdb Tutorial3/ja: DB チュートリアルの第三の部分。複数のデータベースについてのプログラムやログインフォームの使い方を学びます。
  • SQLdb Tutorial4/ja: DB チュートリアルの第四の部分。どのようにデータモジュールを用いるかを学びます。
  • Lazarus Database Overview/ja: Lazarus がサポートしているデータベースについての情報。 データベースごとの記述へのリンクを含みます。
  • SQLdb Package/ja: SQLdb パッケージについての情報
  • SQLdb Programming Reference/ja: SQLdb データベースコンポーネントの入出力の概要
  • SqlDBHowto/ja: SQLdb パッケージを用いることについての情報
  • Working With TSQLQuery/ja: TSQLQuery についての情報