【.NET】WindowsFormsAppとSQLiteを接続する


はじめに

.NET Core(WindowsFormsApp)でデスクトップアプリを開発する際にデータベースを利用する方法を解説します。
合わせて、コード上でデータベースのデータを取得する方法(クエリ発行)を解説します。
開発環境はVisual Studio 2019EntityFrameworkCoreを使います。
データベースはSQLiteを使っています。
補足には外部キー制約の設定、データベースやテーブルの削除方法を追記しています。

環境

  • Visual Studio 2019
  • WindowsFormsApp(.NET Core C#)
  • EntityFrameworkCore(以下、EFCore)
  • SQLite

目次

  1. Installerでツールセットをインストール
  2. WindowsFormsAppプロジェクトを作成
  3. クラスライブラリプロジェクトを作成し、EFCoreをインストール
  4. プロジェクト間の依存関係を設定
  5. モデルを書き、データベースを作成
  6. データベースからデータを取得する
  7. 補足
    1. Microsoft.EntityFrameworkCore.○○について
    2. 主キー、外部キー制約の設定
    3. データベースの削除

1. Installerでツールセットをインストール

はじめに、VisualStudioInstallerでデータベースを扱うために必要となるツールをインストールします。
必要となるのは、「データの保存と処理」というツールセットです。
これによって、データベースを扱うために必要となるクラスライブラリというプロジェクトが作成できるようになります。
「更新」と表示されている場合は、一度更新した後に変更できます。

2. WindowsFormsAppプロジェクトを作成

アプリの本体となるWindowsFormsAppプロジェクトを作成します。

プロジェクト名、プロジェクトのディレクトリ、ソリューション名などは自由に決めて下さい。

3. クラスライブラリプロジェクトを作成し、EFCoreをインストール

今度は2で作成したソリューション内にクラスライブラリプロジェクトを作成します。


クラスライブラリはクラスライブラリ(.NET Core)を作成してください。

クラスライブラリを作成したら、次にNuGetパッケージからEFCoreをインストールします。
インストールするのは以下の3つです。これらが何なのかは補足で解説します。

  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.EntityFrameworkCore.Sqlite

「クラスライブラリプロジェクトを右クリック」→「NuGetパッケージの管理」→「参照」

4. プロジェクト間の依存関係を設定

3つのツールをインストールできたら、WindowsFormsAppプロジェクトからクラスライブラリのクラスを扱えるようにします。
このままでは、WindowsFormsAppプロジェクトからクラスライブラリのクラスを呼び出すことができないので、フォーム内でイベントが発生した際にデータベースを操作したいときなどに不便です。(ボタンがクリックされたら、保持データをデータベースに追加する等)
そのため、以下の設定をすることでクラスライブラリのクラスを扱えるようになり、フォーム内で発生した各種イベントからデータをデータベースに追加したり取得したりできます。

「WindowsFormsAppプロジェクトの依存関係を右クリック」→「プロジェクト参照の追加」→「該当するライブラリにチェック」

5. モデルを書き、データベースを作成

ここまで来たら、いよいよデータベースを作成していきます。
まずはクラスライブラリのClass1.csデータベースの構成テーブルの構造を書いていきます。
以下、記事の読みやすさの都合上、Class1.csをModel.csに置き換えて解説します。

Model.cs
using System;
using  Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

namespace ClassLibrary1
{
    public class sampleDbContext : DbContext
    {
        public DbSet<Blog> Blogs;
        public DbSet<Post> Posts;

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite("Data Source=sample.db");
        }

        public class Blog
        {
            public int BlogId { get; set; }
            public string Url { get; set; }
            public List<Post> Posts { get; } = new List<Post>();    
        }

        public class Post
        {
            public int PostId { get; set; }
            public string Title { get; set; }
            public string Content { get; set; }
            public int BlogId { get; set; }
            public Blog Blog { get; set; }      
        }
    }
}

各クラス・変数について以下の表にまとめます。

クラス 内部クラス 変数 メソッド 内容
sampleDbContext データベースへの基本操作(追加、検索、削除など)を扱うクラス、このクラスをインスタンス化してデータベースを操作する
Blogs Blogテーブルにある既存のデータがオブジェクトとして格納されている
Posts Blogテーブルにある既存のデータがオブジェクトとして格納されている
OnConfiguring データベース接続に必要な情報(接続文字列、データベース名、ログイン情報)を記載する
Blog テーブル「Blog」の構成(カラムや制約など)が記述されている
BlogId ブログのIDが格納される、主キー制約を持つ
Url ブログのURLが格納される
Posts ブログ内の記事情報(Post情報)がオブジェクトとして格納される
Post テーブル「Post」の構成(カラムや制約など)が記述されている
PostId 記事のIDが格納される、主キー制約を持つ
Title 記事のタイトルが格納される
Content 記事の本文が格納される
BlogId 記事があるブログのIDが格納される、外部キー制約を持つ(親はBlogのBlogId)
Blog 記事があるブログの情報がオブジェクトとして格納される

DbContextクラスを継承したsampleDbContextクラスはアプリとデータベースを連携させる架け橋のようなものです。

モデルを書き終えたらパッケージマネージャーコンソールで以下のコマンドを順に実行します。

  1. Add-Migration migration_name
  2. update-database

1を実行することでマイグレーションファイルが指定した名前で作成されます。
2を実行することでマイグレーションファイルをもとにクエリが発行され、データベースやテーブルが作成・変更されます。
初回のマイグレーションではModel.csの内容からクエリが発行され、データベースやテーブルが作成されます。
それ以降は、直近のマイグレーションと現在のModel.csの差異からクエリが発行され、データベースやテーブルが変更されます。

6. データベースからデータを取得する

データベースを作成し適当にデータを格納したら、WindowsFormsAppプロジェクトからそのデータを取り出して表示してみましょう。
今回はフォーム内の任意ボタンがクリックされた時に、上記のModel.csで作成されたBlogテーブルからすべてのブログのBlogIdとUrlを取得しコンソールに表示する方法を考えます。
以下はLINQクエリを用いて書いています。
メソッド構文での書き方はこちらを参照ください。

Form1.cs
//以下を追加でusingする
using System.Linq; 
using ClassLibrary1; //クラスライブラリプロジェクト名を書く。依存関係を設定後、ライブラリが認識される

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //データベースにデータを追加するボタンクリックイベント
        private void AddButton_Click(object sender, EventArgs e){
        {
            using(var db = new sampleDbContext())
            {
                db.Add(new Blog { Url = "http://sample.com" });
                db.SaveChanges();
            }
        }

        //データベースからデータを取得するボタンクリックイベント
        private void GetButton_Click(object sender, EventArgs e)
        {
            //データベースにクエリを発行するためにDbContextクラスをインスタンス化
            using(var db = new sampleDbContext())
            {
                //格納されているすべてのブログ情報を配列で取得
                var queryAllBlog = from blog in db.Blogs
                                    select blog
                //配列から各オブジェクトを取り出し処理する
                foreach(var data in queryAllBlog){
                    Console.WriteLine(data.BlogId);
                    Console.WriteLine(data.Url);
                    Console.WriteLine(); //改行
                }
            }
        }
    }
}

補足

Microsoft.EntityFrameworkCore.○○について

この記事における3つのパッケージのインストール理由を簡単に説明します。

  • Microsoft.EntityFrameworkCore.Design
    →データベースやテーブルのもとになるモデルファイル(Model.cs)でDbContextクラスを利用するために必要となる。DbContextクラスやその継承クラスはデータの受け皿となる。
  • Microsoft.EntityFrameworkCore.Tools
    →パッケージマネージャーコンソールでAdd-Migrationupdate-databaseなどのコマンドを実行するために必要となる
  • Microsoft.EntityFrameworkCore.Sqlite
    →EFCoreでデータベースとしてSQLiteを利用するときに必要となる

主キー、外部キー制約の設定

EFCoreでは主キー制約や外部キー制約を明示的に示さなくても条件を満たすカラムに自動的に制約が付加されます。
主キー制約は{テーブル名}Idというパターンのカラム名に付加されます。
外部キー制約は主キー制約がある別テーブルのカラムと同じ名前をカラム名にすると付与されます。
5のテーブルだと、主キー制約がBlogのBlogIdとPostのPostIdに、外部キー制約がPostのBlogIdに自動的に付加されます。
もちろん明示的に制約を付加することもできますし、自動的に制約を付加しないように設定することも可能です。

データベースの削除

削除はdrop-databaseでできます。
なお、drop-database -WhatIfで削除されるデータベースを確認できます。実際に削除はされずに確認だけできますので、削除前にしっかり確認しましょう。
データベースやテーブルをいじっていて中身がおかしくなってしまい、再度データベースを一から作成し直したい時に使いましょう。
格納しているデータがないときは良いですが、データもすべて消えますのでどうしても元に戻せなかった時だけ実行してください。

参考サイト