Entity Framework CoreでMariaDB/MySQLに接続する方法

実現したいこと
- C#からMariaDB(≒MySQL)を操作したい。
- C#からDBを操作する方法はいくつかあるが、O/RMとしてEntity Framework Coreを用いる。

結論
Pomelo.EntityFrameworkCore.MySqlを使う
MySQL最新版を利用しているなら、MySql.EntityFrameworkCoreもある。(MySql.Data.EntityFrameworkCoreはディスコン)

どのように進めるか
以下の3つの手法がある。
- 手動でDB側テーブルを作成し(または既存DBを参照し)、手動でモデルのコードを書く
- 手動でDB側テーブルを作成し(または既存DBを参照し)、自動でモデルのコードを生成する → スキャフォールディング
- 手動でモデルのコードを書き、自動でDB側テーブルを作成する → コードファーストアプローチ
今回は既存DBに接続したいので1か2になるが、良い機会なので先に3を試しておく。

3. コードファーストアプローチを試す
以下のブログを参考にテストしてみる。とてもわかりやすい。ありがとうございます!
コンテキストクラスのMySqlServerVersion
をMariaDbServerVersion
に変更。Todoエンティティクラスはそのまま。この2つのクラスを1つのmodel.csファイルにまとめる。
using Microsoft.EntityFrameworkCore;
namespace ConsoleApp1;
internal class TodoContext : DbContext
{
public DbSet<Todo> Todos { get; set; }
// 接続文字列
readonly string connectionString = "server=10.0.0.2;database=todo;user=権限のある誰か;password=ここに埋め込まずに外に書く;";
// MariaDBのバージョン
//readonly MySqlServerVersion serverVersion = new(new Version(8, 0, 36));
readonly MariaDbServerVersion serverVersion = new(new Version(10, x, y));
// DBコンテキストの設定
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseMySql(connectionString, serverVersion);
}
internal class Todo
{
public int Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Pomelo.EntityFrameworkCore.MySqlはReleasedの最新版8.0.2。
Microsoft.EntityFrameworkCore.Toolsも最新版9.0.2をインストールしたところ、Add-Migration InitialCreate
でエラーが発生した。
PM> Add-Migration InitialCreate
Build started...
Build succeeded.
Unable to create a 'DbContext' of type 'TodoContext'. The exception 'Method 'get_LockReleaseBehavior' in type 'Pomelo.EntityFrameworkCore.MySql.Migrations.Internal.MySqlHistoryRepository' from assembly 'Pomelo.EntityFrameworkCore.MySql, Version=8.0.2.0, Culture=neutral, PublicKeyToken=2cc498582444921b' does not have an implementation.' was thrown while attempting to create an instance. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
PM>
EF Coreのドキュメントに
必ず、Microsoft から出荷されたすべての EF Core パッケージの同じバージョンをインストールしてください。[1]
と記載されていたので、Microsoft.EntityFrameworkCore.Tools 9.0.2をアンインストール、Pomeloが要求しているものと同じ8系の最新版8.0.13をインストールし直して再実行。
PM> Add-Migration InitialCreate
Build started...
Build succeeded.
To undo this action, use Remove-Migration.
PM> Update-Database
Build started...
Build succeeded.
Applying migration '20250225054944_InitialCreate'.
Done.
PM>
問題なさそう。事前にDB側でC#専用ユーザを作成して適切な権限付与を行っておけば、create databaseの実行すら不要で、コンテキストクラスで指定したtodo
というdatabaseが作成されている。
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| todo |
+--------------------+
2 rows in set (0.00 sec)
MariaDB [(none)]> use todo;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [todo]> show tables;
+-----------------------+
| Tables_in_todo |
+-----------------------+
| Todos |
| __EFMigrationsHistory |
+-----------------------+
2 rows in set (0.00 sec)
MariaDB [todo]> show create table Todos\G
*************************** 1. row ***************************
Table: Todos
Create Table: CREATE TABLE `Todos` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Name` longtext,
`IsComplete` tinyint(1) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
MariaDB [todo]> show create table __EFMigrationsHistory\G
*************************** 1. row ***************************
Table: __EFMigrationsHistory
Create Table: CREATE TABLE `__EFMigrationsHistory` (
`MigrationId` varchar(150) NOT NULL,
`ProductVersion` varchar(32) NOT NULL,
PRIMARY KEY (`MigrationId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
MariaDB [todo]> select * from __EFMigrationsHistory;
+------------------------------+----------------+
| MigrationId | ProductVersion |
+------------------------------+----------------+
| 20250225054944_InitialCreate | 8.0.2 |
+------------------------------+----------------+
1 row in set (0.00 sec)
PRIMARY KEYも設定されている。
慣例により、Id または <type name>Id という名前のプロパティがエンティティの主キーとして構成されます。[2]
この後、CRUD操作も問題なく動作した。

1. 既存DBを参照し、手動でモデルのコードを書く
モデルのコードで必要なのは、DBとのセッションを表すコンテキストと、テーブルとのマップを示すエンティティ。
ただ、上記例のままではパスワード等がコード直書きとなっていて望ましくない。このような場合、一般的にappsettings.json
が使われるようなので、コンソールアプリでも使えるようにする。
appsettings.json
から値を取得する方法は以下を参考にする。
appsettings.json
の作成は以下を参考にする。(今回汎用ホストは設定しない)
手順は以下の通り
- プロジェクト直下に「JavaScript JSON 構成ファイル」を追加しファイル名を
appsettings.json
とする。 -
appsettings.json
のプロパティで「出力ディレクトリにコピー」の項目を「コピーしない」から「常にコピーする」に変更する。(これでConsoleApp1.csprojに以下が反映される)
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
-
appsettings.json
にconnectionString
を記載する
{
"ConnectionStrings": {
"connectionString": "server=10.0.0.2;database=todo;user=権限のある誰か;password=パスワード;"
}
}
- パッケージのMicrosoft.Extensions.Configuration 9.0.2とMicrosoft.Extensions.Configuration.Json 9.0.2を追加する。
-
appsettings.json
を読み込むようmodel.csを変更する。