Difference between revisions of "SQLdb Tutorial2/ja"

From Lazarus wiki
Jump to navigationJump to search
Line 5: Line 5:
 
== 概要 ==
 
== 概要 ==
  
If you have followed [[SQLdb Tutorial1]], you have a basic grid showing database information.
+
[[SQLdb Tutorial1]]が済んでいるなら、データベースを表示する基本的なグリッドがあるはずだ
While this application works, we can add some refinements on this.
+
このアプリケーションが機能するためには若干の改良を加えることができる。
 
 
 
=== 動的データベース接続 ===
 
=== 動的データベース接続 ===
  
Line 13: Line 12:
 
前述したように、「実際の」アプリケーションでは通常、ユーザーが独自のユーザー名とパスワードを指定できる。
 
前述したように、「実際の」アプリケーションでは通常、ユーザーが独自のユーザー名とパスワードを指定できる。
  
それらを指定できるようにフォームを変更しよう。標準メニューから 2 つの [[TEdit]] を追加します。 名前のプロパティを「ユーザー名」と「パスワード」に設定する。
+
それらを指定できるようにフォームを変更しよう。標準メニューから 2 つの [[TEdit]] を追加する。 名前のプロパティを「ユーザー名」と「パスワード」に設定する。
 
肩越しに覗き見されることに対するセキュリティを確保するには、パスワードの PasswordChar プロパティを * (アスタリスク) に設定する。
 
肩越しに覗き見されることに対するセキュリティを確保するには、パスワードの PasswordChar プロパティを * (アスタリスク) に設定する。
  

Revision as of 15:58, 28 March 2024

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

データベースのポータル

参照:

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

各種データベース

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

概要

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

動的データベース接続

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

それらを指定できるようにフォームを変更しよう。標準メニューから 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 がある。

Editing data using the grid

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

編集

これまで、グリッド内のデータを編集しようとしても、変更は保存されなかった。 これは、「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
    // 開始されたトランザクション内にいる場合のみ。;
    // それ以外の場合は、「非アクティブなデータセットでは操作を実行できません」というメッセージが表示される。
    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.

Embedded database without code changes

Firebird on Windows

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 fbembed.dll embedded Firebird library to fbclient.dll. With this, Lazarus could connect to regular Firebird servers (either on another machine or on your local machine). However, you can also copy the employee.fdb 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.

September 2011: in recent development (SVN) versions of Free Pascal, FPC tries to first load fbembed.dll, so you need not rename fbclient.dll anymore for this to work.

Firebird on Linux/macOS/Unix

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 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.

Other databases

Your database might offer similar functionality. Updates of this wiki for other database systems are welcome.

See also