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

# はじめに
**.NET Core(WindowsFormsApp)**でデスクトップアプリを開発する際に**データベース**を利用する方法を解説します。
合わせて、コード上でデータベースのデータを取得する方法（クエリ発行）を解説します。
開発環境は**Visual Studio 2019**と**EntityFrameworkCore**を使います。
データベースは**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**でデータベースを扱うために必要となるツールをインストールします。
必要となるのは、**「データの保存と処理」**というツールセットです。
これによって、データベースを扱うために必要となる**クラスライブラリ**というプロジェクトが作成できるようになります。
「更新」と表示されている場合は、一度更新した後に変更できます。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598279/482b41b5-805f-5b6a-50e5-a4869c333a20.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598279/77b5958b-4e24-7ce5-fda3-147914b14f59.png)

# 2. WindowsFormsAppプロジェクトを作成
アプリの本体となる**WindowsFormsAppプロジェクト**を作成します。 
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598279/622099ff-f55b-b37c-4eed-2feaf5eee005.png)
プロジェクト名、プロジェクトのディレクトリ、ソリューション名などは自由に決めて下さい。

# 3. クラスライブラリプロジェクトを作成し、EFCoreをインストール
今度は2で作成したソリューション内に**クラスライブラリプロジェクト**を作成します。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598279/fcd9ba09-86cd-fb83-6228-f0408eeeed7f.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598279/65c62781-2f36-e712-ce86-a5feb59c4ae3.png)
クラスライブラリは**クラスライブラリ(.NET Core)**を作成してください。

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

- Microsoft.EntityFrameworkCore.Design
- Microsoft.EntityFrameworkCore.Tools
- Microsoft.EntityFrameworkCore.Sqlite

「クラスライブラリプロジェクトを右クリック」→「NuGetパッケージの管理」→「参照」
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598279/4d6359e5-5d1d-21e5-08f3-5e2ea7f980c4.png)


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

「WindowsFormsAppプロジェクトの依存関係を右クリック」→「プロジェクト参照の追加」→「該当するライブラリにチェック」
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598279/d36bfb0d-33f9-eadb-a5b9-34c408ded42c.png)


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

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

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598279/b1c5874f-4c9f-63e2-876a-3c03947bdda1.png)

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

# 6. データベースからデータを取得する
データベースを作成し適当にデータを格納したら、**WindowsFormsAppプロジェクトからそのデータを取り出して表示**してみましょう。
今回はフォーム内の任意ボタンがクリックされた時に、上記のModel.csで作成された**BlogテーブルからすべてのブログのBlogIdとUrlを取得しコンソールに表示する方法**を考えます。
以下は**LINQクエリ**を用いて書いています。
メソッド構文での書き方は<a href="https://docs.microsoft.com/ja-jp/ef/core/get-started/?tabs=visual-studio" target="_blank">こちら</a>を参照ください。

```cs: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.○○について
この記事における３つのパッケージのインストール理由を簡単に説明します。

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

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

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

# 参考サイト
- <a href="https://docs.microsoft.com/ja-jp/ef/core/get-started/?tabs=netcore-cli" target="_blank">EF Core の概要</a>
- <a href="https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/concepts/linq/basic-linq-query-operations" target="_blank">LINQ クエリの基本操作 (C#)</a>
- <a href="https://docs.microsoft.com/ja-jp/ef/core/miscellaneous/configuring-dbcontext" target="_blank">DbContext の構成</a>
- <a href="https://docs.microsoft.com/ja-jp/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key" target="_blank">リレーションシップ</a>