.NET MAUIとCleanArchitectureで簡単なアプリを作成してみる4～実装2～

[.NET MAUIとCleanArchitectureで簡単なアプリを作成してみる4～実装1～](https://qiita.com/GOROGOROMOGUMOGU/items/3803ca4a09c0800b1c86)の続き
# Domainを実装する
#### 新しいプロジェクトを追加する
種類「クラスライブラリ」
プロジェクト名「MauiApp1.Domain」
フレームワーク「.NET8」
フォルダ構成は[フォルダ構成を決める(MauiApp1.Domain)](https://qiita.com/GOROGOROMOGUMOGU/items/3803ca4a09c0800b1c86#%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E6%A7%8B%E6%88%90%E3%82%92%E6%B1%BA%E3%82%81%E3%82%8B)の通り
#### エンティティを作成する
体調情報エンティティを作成する
```c#:Health.cs
    public class Health
    {
        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="id"></param>
        /// <param name="recordDate"></param>
        /// <param name="heartNumber"></param>
        public Health(int id, DateTime recordDate, int heartNumber)
        {
            Id = id;
            RecordDate = recordDate;
            HeartNumber = heartNumber;
        }

        /// <summary>
        /// ID
        /// </summary>
        public int Id { get; }
        /// <summary>
        /// 記録日付
        /// </summary>
        public DateTime RecordDate { get; }
        /// <summary>
        /// ハート数
        /// </summary>
        public int HeartNumber { get; }
    }
```
#### Repositoryインタフェースを作成する
```c#:IHealthRepository.cs
    public interface IHealthRepository
    {
        /// <summary>
        /// 記録日付を指定して体調情報を取得する
        /// </summary>
        /// <param name="recordDate"></param>
        /// <returns></returns>
        Health? Find(DateTime recordDate);

        /// <summary>
        /// 期間を指定して体調情報を取得する
        /// </summary>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        IEnumerable<Health> Find(DateTime startDate, DateTime endDate);

        /// <summary>
        /// 体調情報を保存する
        /// </summary>
        /// <param name="health"></param>
        void Save(Health health);
    }
```
便宜上、Interactorは後で作成します。
# Infrastructureを実装する
#### 新しいプロジェクトを追加する
種類「クラスライブラリ」
プロジェクト名「MauiApp1.SqlInfrastructure」
フレームワーク「.NET8」
フォルダ構成は[フォルダ構成を決める(MauiApp1.SqlInfrastructure)](https://qiita.com/GOROGOROMOGUMOGU/items/3803ca4a09c0800b1c86#%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E6%A7%8B%E6%88%90%E3%82%92%E6%B1%BA%E3%82%81%E3%82%8B)の通り
「MauiApp1.Domain」をプロジェクト参照する
#### Sqliteをインストールする
NuGetからインストールします。
「Microsoft.Data.Sqlite.Core」を選択してインストールする
![SQlite.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674221/8dde7858-e191-c144-2aee-9b50c1fc9efa.png)
「You need to call SQLitePCL.raw.SetProvider().」みたいなエラーになることがあるので、
「SQLitePCLRaw.bundle_e_sqlite3 2.1.7」もインストールする
![SQlitePCL.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3674221/ea047df0-1fca-adce-9db9-7b82367a07d6.png)

#### DBを作成する
DBとテーブルを作成するコードをMauiApp1.SqlInfrastructure直下に作っておく
```c#:Sqlite.cs
using Microsoft.Data.Sqlite;

    public static class Sqlite
    {
        /// <summary>
        /// 接続文字列
        /// </summary>
        internal static string ConnectionString = "Data Source={0}";

        /// <summary>
        /// データベースを作成する
        /// </summary>
        /// <param name="db"></param>
        public static void CreateDB(string db)
        {
            ConnectionString = string.Format(ConnectionString, db);

            using (var connection = new SqliteConnection(ConnectionString))
            {
                connection.Open();

                using (var command = connection.CreateCommand())
                {
                    // テーブルを作成する
                    command.CommandText = "CREATE TABLE IF NOT EXISTS Health ( id INTEGER NOT NULL PRIMARY KEY, record_date TEXT NOT NULL, heart_number INTEGER NOT NULL);";
                    command.ExecuteNonQuery();
                }
            }
        }
    }
```
#### Repositoryを実装する

```c#:HealthRepository.cs
using MauiApp1.Domain.Model.Healths;
using Microsoft.Data.Sqlite;

    public class HealthRepository : IHealthRepository
    {
        /// <summary>
        /// 記録日付を指定して体調情報を取得する
        /// </summary>
        /// <param name="recordDate"></param>
        /// <returns></returns>
        public Health? Find(DateTime recordDate)
        {
            using (var connection = new SqliteConnection(Sqlite.ConnectionString))
            {
                connection.Open();

                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "SELECT * FROM Health WHERE record_date = $record_date";
                    command.Parameters.AddWithValue("$record_date", recordDate);
                    var reader = command.ExecuteReader();

                    if (reader.Read())
                    {
                        return new Health(
                            (int)((long)reader["id"]),
                            recordDate,
                            (int)((long)reader["heart_number"])
                        );
                    }
                    else
                    {
                        return null;
                    }
                }
            }
        }

        /// <summary>
        /// 期間を指定して体調情報を取得する
        /// </summary>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public IEnumerable<Health> Find(DateTime startDate, DateTime endDate)
        {
            using (var connection = new SqliteConnection(Sqlite.ConnectionString))
            {
                connection.Open();

                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "SELECT * FROM Health WHERE record_date BETWEEN $start_date AND $end_date";
                    command.Parameters.AddWithValue("$start_date", startDate);
                    command.Parameters.AddWithValue("$end_date", endDate);
                    var reader = command.ExecuteReader();

                    var results = new List<Health>();
                    while (reader.Read())
                    {
                        DateTime.TryParse(reader["record_date"] as string, out DateTime recordDate);

                        var health = new Health(
                            (int)((long)reader["id"]),
                            recordDate,
                            (int)((long)reader["heart_number"])
                        );

                        results.Add(health);
                    }
                    return results;
                }
            }
        }

        /// <summary>
        /// 体調情報を保存する
        /// </summary>
        /// <param name="health"></param>
        public void Save(Health health)
        {
            using (var connection = new SqliteConnection(Sqlite.ConnectionString))
            {
                connection.Open();

                // Idの有無を確認する
                bool isExist;
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = "SELECT * FROM Health WHERE id = $id";
                    command.Parameters.AddWithValue("$id", health.Id);
                    var reader = command.ExecuteReader();
                    isExist = reader.Read();
                }

                using (var command = connection.CreateCommand())
                {
                    if (isExist)
                    {
                        // Idが存在する場合は更新する
                        command.CommandText = "UPDATE Health SET heart_number = $heart_number WHERE id = $id";
                        command.Parameters.AddWithValue("$id", health.Id);
                        command.Parameters.AddWithValue("$heart_number", health.HeartNumber);
                    }
                    else
                    {
                        // Idが存在しない場合は追加する
                        command.CommandText = "INSERT INTO Health(record_date, heart_number) VALUES($record_date, $heart_number)";
                        command.Parameters.AddWithValue("$record_date", health.RecordDate);
                        command.Parameters.AddWithValue("$heart_number", health.HeartNumber);
                    }

                    command.ExecuteNonQuery();
                }
            }
        }
    }
```
 
# 参考にしたURL
[実践クリーンアーキテクチャ](https://nrslib.com/clean-architecture/)
[Microsoft.Data.Sqlite 概要](https://learn.microsoft.com/ja-jp/dotnet/standard/data/sqlite/?tabs=netcore-cli)
# まとめ
今回はDomain、Infrastructureを実装しました。
次はInteractorを実装します。
[.NET MAUIとCleanArchitectureで簡単なアプリを作成してみる4～実装3～](https://qiita.com/GOROGOROMOGUMOGU/items/097e0c26f167f27b35c4)