砂漠の旅人(たびと)

UNIX / MS-DOS 時代から電脳砂漠を旅しています

【前編】.NET 6 から SQLite、PostgreSQL、MySQL、SQL Server、Oracle にEntity Framework Core で接続する

こんにちは、たびとです。

前回は、ASP.NET Core 6.0 の Entity Framework Core に関して、 Visual Studio 2022 を使って新規プロジェクトで確認しました。

今回は、主要なデータベースに関して、Entity Framework Core による データベースアクセスを試してみようと思います。

この記事の対象者

  • .NET 6 に興味のある方、これから使う予定のある方
  • 各データベースと Entity Framework Core の違いに興味のある方
  • PostgreSQL および MySQL を docker で構築してみたい方

Entity Framework Core によるデータベースアクセス

C# による Entity Framework Core の簡単なソースコードSQLite, PostgreSQL, MySQL, SQL Server, Oracle を使って、 データベース接続以外は同じコードで実行できるのかを試します。

以下の4項目に関して同じコードが適用できるのかを試してみることにします。

  • データベース削除(EnsureDeletedAsync)
  • データベース作成(EnsureCreatedAsync)
  • テーブルへの書き込み(SaveChangesAsync)
  • テーブルからの読み込み()

C#ソースコードは以下の条件で作成します。

  • .NET 6 のコンソールアプリ(.NET Core)
  • Main なしのシンプルなコード(最上位レベルステートメントと呼ぶらしい)
  • DB接続以外は、できる限り同じコード

データベースは NuGet からパッケージをインストールするだけで使える SQLite を除き、 WSL2/Ubuntu 上の docker で構築することにします。 このとき、Dockerfile や docker-compose.yml を使わずに、 コマンドだけで、できるだけ簡単に構築できるようにします。

WSL2/Ubuntu 上の Docker 構築は、以前の記事も参考にしてください。

sabakunotabito.hatenablog.com

SQLite による Entity Framework Core

SQLite による簡単な Entity Framework Core のソースコードを実行します。

SQLite 構築

SQLite は、NuGet パッケージをインストールするだけなので、 インストーラや docker でデータベースを構築する必要はありません。 SQLite は手軽なので、チョッとしたツールを作成するときのデータベースとしては最適だと思います。

SQLite 用のソースコード

NuGet によりインストールしたパッケージは、 Microsoft.EntityFrameworkCore.Sqlite 6.0.0 となります。

using Microsoft.EntityFrameworkCore;

await using var context = new SampleContext();

await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

context.Samples.Add(new Sample() { Id = 12345, Name = "たびと" });
await context.SaveChangesAsync();

foreach (var item in context.Samples)
    Console.WriteLine($"{item.Id}: {item.Name}");

public class SampleContext : DbContext
{
    public DbSet<Sample> Samples { get; set; }

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

public class Sample
{
    public int Id { get; set; }

    public string Name { get; set; }
}

実行後に生成された SQLiteDDL

ソースコードを実行した後に作成されるテーブル情報(DDL)は、以下の通りです。

CREATE TABLE "Samples" (
    "Id" INTEGER NOT NULL CONSTRAINT "PK_Samples" PRIMARY KEY AUTOINCREMENT,
    "Name" TEXT NOT NULL
);

ちなみに、sample.db はパスを指定しないと実行ファイルと同じフォルダに出力されます。

PostgreSQL による Entity Framework Core

docker を用いて PostgreSQL を構築し、簡単な Entity Framework Core のソースコードを実行します。

docker による PostgreSQL 構築

docker を用いて、最新の PostgreSQL を起動します。

$ docker run -d --name postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres

上記のデフォルトのデータベースである「postgres」を指定しても、データベースの削除と作成に失敗します。 このため、削除(EnsureDeletedAsync) と 作成(EnsureCreatedAsync) 用に、新規のデータベース「ef」を作り、 このデータベースを対象にします。

PostgreSQL 用のソースコード

SQLite の UseSqlite() を UseNpgsql() に変更し、データベースの接続文字列を記述します。 UseSnakeCaseNamingConvention() は、Npgsql のサイトに掲載されていたもので、 テーブル名・フィールド名をスネークケース形式に置き換えてくれるものです。

PostgreSQL .NET 6 Entity Framework Core のソースコードは以下の通り。

using Microsoft.EntityFrameworkCore;

await using var context = new SampleContext();

await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

context.Samples.Add(new Sample() { Id = 12345, Name = "たびと" });
await context.SaveChangesAsync();

foreach (var item in context.Samples)
    Console.WriteLine($"{item.Id}: {item.Name}");

public class SampleContext : DbContext
{
    public DbSet<Sample> Samples { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseNpgsql("host=localhost;port=5432;database=ef;username=postgres;password=postgres")
                  .UseSnakeCaseNamingConvention();
}

public class Sample
{
    public int Id { get; set; }

    public string Name { get; set; }
}

ビルドに必要な NuGet パッケージは以下の通り。

  • Npgsql.EntityFrameworkCore.PostgreSQL 6.0.1
  • EFCore.NamingConventions 6.0.0

実行後に生成された PostgreSQLDDL

ソースコードを実行した後に作成されるテーブル情報(DDL)は、以下の通りです。 UseSnakeCaseNamingConvention() を削除すると、大文字・小文字が有効になります。

CREATE TABLE public.samples (
    id int4 NOT NULL GENERATED BY DEFAULT AS IDENTITY,
    "name" text NOT NULL,
    CONSTRAINT pk_samples PRIMARY KEY (id)
);

MySQL による Entity Framework Core

docker を用いて MySQL を構築し、簡単な Entity Framework Core のソースコードを実行します。

docker による MySQL 構築

docker から 最新の MySQL を起動します。

$ docker run -d --name mysql -e MYSQL_ROOT_PASSWORD=mysql -p 3306:3306 mysql

DBeaver により MySQL への接続を確認したとき、「SSLを使用する」にチェックを入れて、 「Allow public key retrieval」にチェックを入れないと接続できませんでした。

デフォルトのデータベースである「sys」を指定しても、データベースの削除と作成に失敗します。 このため、削除(EnsureDeletedAsync) と 作成(EnsureCreatedAsync) 用に、新規のデータベース「ef」を作り、 このデータベースを対象にします。

MySQL 用のソースコード

SQLite の UseSqlite() を UseMySql() に変更し、データベースの接続文字列とデータベースの版数を指定します。 LogTo()、EnableSensitiveDataLogging()、EnableDetailedErrors() は、 今回使用した Pomelo.EntityFrameworkCore.MySql のサンプルに記載されたモノを使っています。 これを使うとコンソールに詳細なログが出力されるようになります。

それと、本家のパッケージよりも、Pomelo.EntityFrameworkCore.MySql の方が人気があるようです。

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

await using var context = new SampleContext();

await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

context.Samples.Add(new Sample() { Id = 12345, Name = "たびと" });
await context.SaveChangesAsync();

foreach (var item in context.Samples)
    Console.WriteLine($"{item.Id}: {item.Name}");

public class SampleContext : DbContext
{
    public DbSet<Sample> Samples { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseMySql("server=localhost;user=root;password=mysql;Database=ef",
                            new MySqlServerVersion(new Version(8, 0, 27)))
                  .LogTo(Console.WriteLine, LogLevel.Information)
                  .EnableSensitiveDataLogging()
                  .EnableDetailedErrors();
}

public class Sample
{
    public int Id { get; set; }

    public string Name { get; set; }
}

実行後に生成された MySQLDDL

ソースコードを実行した後に作成されるテーブル情報(DDL)は、以下の通りです。

CREATE TABLE `Samples` (
  `Id` int NOT NULL AUTO_INCREMENT,
  `Name` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=12346 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

まとめ

前編では、SQLitePostgreSQLMySQL を使って、.NET 6 で Entity Framework Core を 作成した場合、どれぐらい違いがでるのかを確認しましたが、 DbContext の UseXxx メソッドの変更だけで、簡単に変更できることがわかりました。

後編では、今回と同様のソースコードを用いて、 SQL ServerOracle を試していきます。

sabakunotabito.hatenablog.com

今後は、Entity Framework Core へのシフトが加速すると、 データベースの移行が簡単になるのかもしれません。

最後に参考サイトを掲載しておきます。

では、皆さん、よい旅を。

参考サイト