WinFormのC#でSQLiteのDI化
■はじめに
WinFormのC#でSQLiteリバース エンジニアリングの続き
まとめにも書いたけど、DBContextとEntityが自動生成出来たので・・・
使ってみると冗長なコードが増えるので
ServiceCollection(DI)を使って、ごにょごにょしてみた
■環境情報
OS:Windows11
DB:SQLite3
開発環境:Microsoft Visual Studio Professional 2022 (64 ビット)
.net core
windows form
■NuGetで必要なものをインストール
Microsoft.EntityFrameworkCore.Tools
Microsoft.EntityFrameworkCore.Design
Microsoft.EntityFrameworkCore.Sqlite.Core
SQLitePCLRaw.bundle_e_sqlcipher
■ServiceCollectionでDI化
毎回、上書きされるリバースエンジニアリングで自動生成されたコードには手を付けないで
DBアクセスとロジッククラスを分けれるように作ってみた。
※インターフェースを準備してとかも考えたけど、今回は見送り
確認用に、下記のようなFormアプリを作ってみた。
検索ボタンを押したら、デバックに出力するだけのもの
WinFormのC#でSQLiteリバース エンジニアリングで先にDBコンテキストとEntityを生成している前提
構成は下記の通り
毎回、DBファイルの場所を書くのは面倒なので定数化
(DATA_PATHは無駄だけど、Dataフォルダを作る予定なのでお許しを)
1 2 3 4 5 6 7 8 9 10 11 |
namespace SqliteTest002 { public static class CommonConstants { public static readonly string APPLICATION_PATH = AppDomain.CurrentDomain.BaseDirectory; public static readonly string DATA_PATH = APPLICATION_PATH + ""; public static readonly string DB_NAME = @"SqliteTest.db"; public static readonly string DB_PATH = DATA_PATH + DB_NAME; public static readonly string DB_PASSWORD = ""; } } |
DBコンテキストを継承して作成
リバースして出来たコードは物理パスそのままだし、パスワード設定時にも対応出来るように考慮
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using SqliteTest002.Models; namespace SqliteTest002.Daoes { public partial class SqliteContext : SqliteTestContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var connectionString = new SqliteConnectionStringBuilder { DataSource = CommonConstants.DB_PATH, Mode = SqliteOpenMode.ReadWriteCreate, Password = CommonConstants.DB_PASSWORD }.ToString(); optionsBuilder.UseSqlite(new SqliteConnection(connectionString)); } } } |
データアクセス用のBaseクラス作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
using System.Diagnostics; namespace SqliteTest002.Daoes { public class DaoBase { protected static SqliteContext _context = new SqliteContext(); public SqliteContext GetContext() { return _context; } public DaoBase(SqliteContext context) { if (_context != context) { _context = context; } } } } |
データアクセスクラス作成
(ココにtestテーブルに関するコードを書く)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
using System.Diagnostics; using SqliteTest002.Models; namespace SqliteTest002.Daoes { public class TestDao : DaoBase { public TestDao(SqliteContext context) : base(context) { } public Test GetFirst() { Test test = _context.Tests.First(); Debug.WriteLine(test.Userid); Debug.WriteLine(test.Password); return test; } } } |
ServiceCollectionを使ってDI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
using Microsoft.Extensions.DependencyInjection; using SqliteTest002.Daoes; using System.Diagnostics; namespace SqliteTest002 { public partial class Form1 : Form { private readonly TestDao testDao; public Form1() { InitializeComponent(); IServiceCollection services = new ServiceCollection(); services.AddDbContext<SqliteContext>(); services.AddSingleton<TestDao>(); var provider = services.BuildServiceProvider(); testDao = provider.GetRequiredService<TestDao>(); } private void button1_Click(object sender, EventArgs e) { testDao.GetFirst(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { testDao.GetContext().Dispose(); } } } |
これで、DBアクセスをクラスに切り出すことが出来る。
■まとめ
とりあえず、やりたい事が出来た。
自動生成されたDBコンテキストを使わず、
自前で書けばデータアクセスクラスにちゃんと意味を持たせることが出来るんだけど
自動生成の意味がエンティティだけになるから悩ましい(DBコンテキスト生成プログラム作れば良いんだけど)
※カスタムリバースエンジニアリング コレを使ってテーブル毎にDBコンテキスト作成出来ないかなぁ
自前で書くなら
『果て無きC#への探求心』さんが良さげなクラス設計してたので参考までに