このヘージと関連するページ一覧

  • SQLite + System.Data.Linq 導入編
  • SQLite + System.Data.Linq 同時実行制御が不十分な場合
  • SQLite + System.Data.Linq 同時実行制御

  • このページの最終更新日 2020/10/25

    SQLite + System.Data.Linq 導入編

     SQLiteはサーバーを必要とせず、ローカルでアプリケーションに組み込んで利用できるデータベースです。もちろん、サーバーにSQLiteデータベースファイルを保存しておき、複数のユーザーでデータを共有することも可能です。SQLServerやMySqlなどのサーバーで使用される主要なデータベースのように同時実行制御に対する機能は多くはありませんが、複数のユーザーの同時更新によるトラブルを避けるような設計にすることは可能です。
     ここではWindowsアプリでSQLiteを扱う課題として、「データベーススペシャリスト平成26年度春季 午後Ⅰ問2」の会議室の予約システムに関する出題のアプリケーションを実際に作成してみることにします。ソリューション名は「ReservationConferenceRoom」とします。

    1. VisualStudioでSQLiteを使うための設定

     VisualStudioでSQLite.dllを使うために設定を行います。「ツール」タブをクリックして、「NuGetパッケージマネージャー」>「ソリューションのNuGetパッケージの管理」をクリックします。するとpic.2のような画面が表示されます。

    NuGetパッケージマネージャーの呼び出し

    - pic.1 -

     pic.2画面で①参照をクリックし、②の検索テキストボックスに「SQLite」と入力してEnterキーを押します。SQLiteに関するパッケージの一覧が表示されますので③の「System.Data.SQLite」の項目をクリックし、④のチェックボックスにチェックマークを入れます。最後に⑤の「インストール」ボタンをクリックします。

    VisualStudioでSQLiteをインストールする手順

    - pic.2 -

     最後にソリューションエクスプローラーから、「参照」>「参照の追加」を開き pic.3のようにSystem.Data.Linqの項目にチェックを入れておきます。これでVisualStudioからSQLiteを扱うための設定はひとまず終了です。

    System.Data.Linqにチェックマークを入れる

    - pic.3 -


    2. DatabaseテーブルをDataGridViewに表示する

     第2節ではSQLiteで会議室予約テーブルを作成し、WindowsFormでテーブル内のデータを表示するところまで完成させましょう。データの表示はDataGridViewを使用します。
     まず、データベーススペシャリストの試験問題に基づいてテーブルを作成していきます。試験問題ではもう少し複雑なのですが、ひとまずcode.1のように「会議室番号」「予約日」「予約開始時刻」「予約終了時刻」の4つのカラムを持っている「会議室予約」テーブルを定義します。執筆者としてはクラス名や変数名を日本語で書くのはあまり好ましいと思わないのですが、ここでは対応を解り易くするため日本語で書き進めることにします。試験問題では「会議室番号」「予約日」「予約開始時刻」の3つのカラムは複合主キーとなっていますので、これに合わせて対応するプロパティには「IsPrimaryKey = true」と指定するようにします。

    - code.1 - ファイル名「会議室予約.cs」
    using System.Data.Linq.Mapping;
    
    [Table(Name = "会議室予約")]
    public class 会議室予約
    {
        [Column(Name = "会議室番号", IsPrimaryKey = true)]
        public int 会議室番号 { get; set; }
    
        [Column(Name = "予約日", IsPrimaryKey = true)]
        public string 予約日 { get; set; }
    
        [Column(Name = "予約開始時刻", IsPrimaryKey = true)]
        public string 予約開始時刻 { get; set; }
    
        [Column(Name = "予約終了時刻")]
        public string 予約終了時刻 { get; set; }
    }
    

     続いてSQLiteデータベースを扱うためのラッパーを用意します。データベースファイルは実行プログラムファイルと同一のフォルダに「ReservationConferenceRoom.db」というファイル名で保存することにします(11行目)。まだデータベースは作成されていないため、プログラムを初めて起動するときには24~35行目が実行され、会議室予約テーブルを作成し、サンプルとして1行分データを挿入するものとします。次回起動するときはデータベースが既に作成されており22行目でコンストラクタを抜けるものとします。
     ところでSQLiteにはSQLServerのDateTime型のように時間を定義するための型は用意されていないため、自力で代案を考える必要があります。ここでは、予約日はyyyy/MM/ddという形式、予約時刻はHH/mmという形式のTEXT型でデータを保存することにします。

    - code.2 - ファイル名「DatabaseWrapper.cs」
    using System.Data.Linq;
    using System.Data.SQLite;
    using IO = System.IO;
    
    public class DatabaseWrapper
    {
        private DataContext _dataContext;
    
        public DatabaseWrapper()
        {
            string dbFilePath = IO.Directory.GetParent(System.Reflection.Assembly.GetExecutingAssembly().Location).FullName + @"\ReservationConferenceRoom.db";
    
            var builder = new SQLiteConnectionStringBuilder()
            {
                DataSource = dbFilePath,
                Version = 3
            };
    
            var connect = new SQLiteConnection(builder.ToString());
            _dataContext = new DataContext(connect);
    
            if (IO.File.Exists(dbFilePath)) { return;}
    
            connect.Open();
            SQLiteCommand createCommand = connect.CreateCommand();
            createCommand.CommandText = "CREATE TABLE 会議室予約(会議室番号 INT,予約日 TEXT,予約開始時刻 TEXT,予約終了時刻 TEXT,PRIMARY KEY(会議室番号,予約日,予約開始時刻))";
            createCommand.ExecuteNonQuery();
    
            SQLiteCommand insertCommand = connect.CreateCommand();
            insertCommand.CommandText = "INSERT INTO 会議室予約(会議室番号,予約日,予約開始時刻,予約終了時刻) VALUES(@会議室番号,@予約日,@予約開始時刻,@予約終了時刻)";
            insertCommand.Parameters.Add(new SQLiteParameter("@会議室番号", 1));
            insertCommand.Parameters.Add(new SQLiteParameter("@予約日", "2018/07/17"));
            insertCommand.Parameters.Add(new SQLiteParameter("@予約開始時刻", "10:00"));
            insertCommand.Parameters.Add(new SQLiteParameter("@予約終了時刻", "11:00"));
            insertCommand.ExecuteNonQuery();
        }
    
        public Table<会議室予約> GetReservationConferenceRoomTable()
        {
            return _dataContext.GetTable<会議室予約>();
        }
    }
    

     データベースを定義したら次はデータベースを表示するものを作成します。SQLiteデータベースの表示・編集ツールはフリーのプログラムでもいくつか存在しますが、ここではWindowsFormアプリケーションのDatagridViewを使用してデータを表示することにします。pic.4 のようにコントロールを配置し、DatagridViewのオブジェクト名は「dgvDatabase」とします。また、Formの拡大・縮小に合わせてDatagridViewも拡大・縮小を行うようにするため、Anchorプロパティに Top, Bottom, Left, Right を加えます。

    DatagridViewのAnchorプロパティを設定

    - pic.4 -

     Formクラスのコンストラクタで、code.3 のように記述します。

    - code.3 - ファイル名「FormMain.cs」
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();
    
            var objDb = new DatabaseWrapper();
            dgvDatabase.DataSource = objDb.GetReservationConferenceRoomTable();
        }
    }
    

     VisualStudioの「開始」ボタンをクリックすると pic.5 のようにSQLiteへ入力したデータが表示されます。

    DatagridViewをFormに貼り付ける

    - pic.5 -


    3. SQLiteにデータを挿入する

     データベースを作成し表示することが出来たら、次はデータを挿入するコードを書いていきましょう。細かい機能は後回しにして、先にプログラムが動作することだけを目標にプログラムを書いていきます。
     pic.6 のようにフォームを作成し、フォーム名は「FormEdit」とします。ラベルとテキストボックスはTableLayoutPanelコントロールを使って体裁を整えます。会議室番号を入力する「tbConferenceRoomId」オブジェクトは入力値を「1」と決め打って、readOnlyプロパティをtrueにしておきます。ボタンのアンカーは右下に設定しておき、Formのサイズが変更された際にも適切にコントロールが配置されるようにします。

    データの入力フォーム

    - pic.6 -


     FormEditクラスの中に code.4 のようにコードを書いていきます。予約日、予約開始時刻、予約終了時刻は時刻の形式になるように入力制限を行うべきですが、ひとます演習を進めるために文字列であれば何でも入力を受け付けるようにしています。14行目のInsertOnSubmitメソッドで挿入したいデータを定義します。21行目のSubmitChangesメソッドは code.5 のDatabaseWrapperクラスに定義します。このDataContextクラスのSubmitChangesメソッドが呼び出された段階でデータの挿入が反映されています。これは内部的にはトランザクションのコミットを行うことと同様のようです。

     OKボタンがクリックされた場合は、データの挿入を行ってから DialogResult プロパティの値を DialogResult.OK(列挙体) にしてからフォームを閉じます。Cancelボタンがクリックされた場合はデータの操作は何も行わずに DialogResult プロパティの値を DialogResult.Cancel にしてフォームをクローズします。DialogResultプロパティは FormEditクラスの継承元であるFormクラスに存在しているプロパティです。ファイルやフォルダを選択するためのOpenFileDialog、FolderBlowserDialog、SaveFileDialogクラスなどでも DialogResultプロパティの値をチェックして、ユーザーが承認したのかキャンセルしたのかを判断します。

    - code.4 - ファイル名「FormEdit.cs」
    public partial class FormEdit : Form
    {
        public FormEdit()
        {
            InitializeComponent();
            btnOk.Click += new EventHandler(OKButtonClick);
            btnCancel.Click += new EventHandler(CancelButtonClick);
        }
    
        public void OKButtonClick(object sender, EventArgs e)
        {
            var objDb = new DatabaseWrapper();
            var objReservationConferenceRoomTable = objDb.GetReservationConferenceRoomTable();
            objReservationConferenceRoomTable.InsertOnSubmit(new 会議室予約()
            {
                会議室番号 = int.Parse(tbConferenceRoomId.Text),
                予約日 = tbReservationDate.Text,
                予約開始時刻 = tbStartTime.Text,
                予約終了時刻 = tbEndTime.Text
            });
            objDb.SubmitChanges();
    
            this.DialogResult = DialogResult.OK;
            this.Close();
        }
    
        public void CancelButtonClick(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }
    }
    
    - code.5 - ファイル名「DatabaseWrapper.cs」
    public class DatabaseWrapper
    {
        private DataContext _dataContext;
    
     ----- ----- (途中略) ----- -----
    
        public void SubmitChanges()
        {
            _dataContext.SubmitChanges();
        }
    }
    

     次に、FormMain に挿入ボタンを追加して、挿入ボタンがクリックされた場合にEditFormが表示されるようにします。挿入ボタンのオブジェクト名は「btnInsert」とします。また、DatagridViewのプロパティ値を

    • AllowUserToAddRows → False
    • SelectionMode → FullRowSelect
    • RowHeadersVisible → False
    と変更してDatagridViewの表示形式を整えておきます。

    FormMainへ挿入ボタンを追加し、DatagridViewのプロパティを変更する

    - pic.7 -

     挿入ボタンをクリックすると、InsertButtonClickメソッドが実行され16行目の ShowDialogメソッドで FormEditフォームが表示されます。フォームを表示する方法としてはこの例のように ShowDialogメソッドを使用する方法と、Showメソッドを使用する方法があります。FormEditフォームをShowDialogで表示した場合は、それ以降のコードはFormEditフォームが閉じられるまで実行されずMainFormの操作も行うことが出来なくなりますが。これに対してShowメソッドで表示した場合はそれ以降のコードも実行され、FormEditフォームもFormMainフォームも共に操作可能な状態になります。ShowDialogメソッドで表示する方法を「モーダル」、Showメソッドで表示する方法は「モードレス」と呼ばれます。Webページ関連の教科書でも「モードレスダイアログの作り方」などの話が載っていたりするので言葉は覚えておきましょう。
     17-19行目のようにFormEditフォームでOKボタンがクリックされた場合にはDatagirdViewを更新して挿入されたデータを表示させるようにします。

    - code.6 - ファイル名「FormMain.cs」
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();
    
            var objDb = new DatabaseWrapper();
            dgvDatabase.DataSource = objDb.GetReservationConferenceRoomTable();
    
            this.btnInsert.Click += new EventHandler(InsertButtonClick);
        }
    
        public void InsertButtonClick(object sender, EventArgs e)
        {
            var objFormEdit = new FormEdit();
            if (objFormEdit.ShowDialog() != DialogResult.OK) { return; }
            var objDb = new DatabaseWrapper();
            dgvDatabase.DataSource = objDb.GetReservationConferenceRoomTable();
        }
    }
    

     フォームのレイアウトを作成し、コードも書き終わったらプログラムが意図通りに実行されるか確認してみます。①FormMainフォームの挿入ボタンをクリックするとFormEditが表示されます。②FormEditのテキストボックスに適当に「あいうえ…」と入力して③OKボタンをクリックします。

    プログラムの実行確認その1。EditFormが表示される。

    - pic.8 -

     pic.9 のように挿入されたデータがDatagridViewに反映されることを確認します。次回からは、予約日や時刻の入力制限を適切に行い、さらにSQLiteでの同時実行制御について解説していくことにします。

    プログラムの実行確認その2。挿入したデータが反映される。

    - pic.9 -