こんにちは、たびとです。
前回は、SQLite, PostgreSQL, MySQL を使った Entity Framework Core による簡単な C# のソースコードを使って、 実行後に、どんなDDLが生成されるのかを確認しました。
今回は、SQL Server および Oracle を確認していきます。
この記事の対象者
- .NET 6 に興味のある方、これから使う予定のある方
- 各データベースと Entity Framework Core の違いに興味のある方
- SQL Server と Oracle を docker で構築してみたい方
SQL Server による Entity Framework Core
docker を用いて SQL Server を構築し、簡単な Entity Framework Core のソースコードを実行します。
docker による SQL Server 構築
docker を用いて、最新の PostgreSQL を起動します。 簡単なパスワードだと失敗するため、注意してください。
$ docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=@Passw0rd" \ -p 1433:1433 --name sql1 -h sql1 \ -d mcr.microsoft.com/mssql/server:2019-latest
デフォルトではデータベース削除と作成に失敗するため、 新規にデータベース「ef」を作成します。
DBeaver などのツールから接続する場合、localhost で接続できますが、 C# から接続する場合、WSL2/Ubuntu 側の IP アドレスを指定する必要があります。 以下のコマンドを使って、IPv4 アドレスを取得します。
$ ip addr show dev eth0 | grep inet inet 172.18.93.234/20 brd 172.18.95.255 scope global eth0 inet6 fe80::215:5dff:fe9e:379f/64 scope link
SQL Server 用のソースコード
SQLite の UseSqlite() を UseSqlServer() に変更し、
データベースの接続文字列を指定します。
このとき、ホスト名は「localhost」ではなく、
前述の ip
コマンドで取得した IP アドレスを指定します。
NuGet によりインストールしたパッケージは、 Microsoft.EntityFrameworkCore.SqlServer 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.UseSqlServer("Data Source=172.18.93.234,1433;Initial Catalog=ef;User ID=SA;Password=@Passw0rd"); } public class Sample { public int Id { get; set; } public string Name { get; set; } }
実行すると以下の例外が表示されました。
SqlException: Cannot insert explicit value for identity column in table 'Samples' when IDENTITY_INSERT is set to OFF.
Id は自動採番されるようになっているようです。 詳細は Microsoft のサイトを参考にしてください。
SET IDENTITY_INSERT (Transact-SQL) - SQL Server | Microsoft Docs
ソースから、Id に値を設定している個所を削ります。
context.Samples.Add(new Sample() { Name = "たびと" });
これで正常に動作するようになりました。 Id は 1 からの自動採番となります。 これは、SQL Server 特有の現象で、他のデータベースでは発生しませんでした。
実行後に生成された SQL Server の DDL
ソースコードを実行した後に作成されるテーブル情報(DDL)は、以下の通りです。 Id には、自動採番用の IDENTITY プロパティが付いています。
CREATE TABLE ef.dbo.Samples ( Id int IDENTITY(1,1) NOT NULL, Name nvarchar COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, CONSTRAINT PK_Samples PRIMARY KEY (Id) );
Oracle による Entity Framework Core
docker を用いて Oracle を構築し、簡単な Entity Framework Core のソースコードを実行します。
docker による Oracle Express Edition (XE) 構築
今回は、 Oracle Database 21c Express Edition (XE) を構築します。 Oracle 21c XE の rpm と docker イメージを作成する資材をダウンロードし、 docker イメージを作成します。
昔はXE のダウンロードに認証が必要でしたが、 現在は認証なしでダウンロードできるようになりました。
$ mkdir oralce $ cd oracle $ git clone https://github.com/oracle/docker-images $ cd docker-images/OracleDatabase/SingleInstance/dockerfiles/21.3.0 $ wget https://download.oracle.com/otn-pub/otn_software/db-express/oracle-database-xe-21c-1.0-1.ol8.x86_64.rpm $ cd .. $ ./buildContainerImage.sh -v 21.3.0 -x -i
docker イメージ完成まで、遅いマシンだと 30 分以上かかります。 イメージ完成後、Oracle 21c XE コンテナを起動します。
$ docker run -e "ORACLE_PWD=oracle" -p 1521:1521 --name oracle -h oracle -d oracle/database:21.3.0-xe
ここでも、データベースが使えるようになるまでしばらく待ちます。
以下のメッセージが表示されるまで、docker logs
コマンドで実行ログを表示します。
終了するには、Ctrl + C
キーを押してください。
$ docker logs -f oracle ~ 途中省略 ~ ######################### DATABASE IS READY TO USE! ######################### ~ 以下省略 ~
Oracleへの接続
DBeaver などのツールで、Oracle 21c XE に接続します。 今回は、SID の XE ではなく、PDB の XEPDB1 を使います。
- Host: localhost
- Port: 1521
- Database: XEPDB1 (Service Name)
- ユーザ名: sys
- Role: SYSDBA
スキーマの追加
新しくスキーマ「ef」を作り、パスワードはコンテナと同じにします。 スキーマ作成後、SQL エディタ等で権限を与えます。
grant connect to ef; grant resource to ef; grant dba to ef;
以上で Oracle 側の準備は完了です。
Oracle 用のソースコード
SQLite の UseSqlite() を UseOracle() に変更し、データベースの接続文字列を記述します。
NuGet によりインストールしたパッケージは、 Oracle.EntityFrameworkCore 6.21.4 となります。
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.UseOracle("User ID=EF;Password=oracle;Data Source=localhost/XEPDB1"); } public class Sample { public int Id { get; set; } public string Name { get; set; } }
実行後に生成された Oracle の DDL
ソースコードを実行した後に作成されるテーブル情報(DDL)は、以下の通りです。
CREATE TABLE "EF"."Samples" ( "Id" NUMBER(10,0) GENERATED BY DEFAULT ON NULL AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE, "Name" NVARCHAR2(2000) NOT NULL ENABLE, CONSTRAINT "PK_Samples" PRIMARY KEY ("Id") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "USERS" ENABLE ) SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "USERS" ; CREATE UNIQUE INDEX "EF"."PK_Samples" ON "EF"."Samples" ("Id") PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "USERS" ;
他のデータベースは数行で割とイメージ通りに出力されましたが、 Oracle は過剰とも思えるぐらい大量に出力されました。
各データベースの特徴
前編・後編を通じて、それぞれのデータベースの特徴を記述します。
SQLite
- NuGet インストールだけで、データベースを利用できる。
- 運用管理端末など、チョッとしたツール作成時に重宝しそう。
PostgreSQL 14.1
- 小文字が原則のようなので、UseSnakeCaseNamingConvention() が便利である。
MySQL 8.0.27
- Docker コンテナにDBeaver等から接続するとき、「SSL、Allow public key retrieval」に気を付ける。
- 本家か Pomelo の Entity Framework を使うべきかを悩む。
SQL Server 2019
- Dokcer で、Linux版の SQL Server が利用できる。
- Docker コンテナに C# から接続する場合、WSL2/Ubuntu の IP アドレスを指定する。
- Int のキーを定義すると、自動採番プロパティが採用された。
Oracle Database 21c XE
- Docker 用のイメージを作るのに時間がかかる。
- Dokcer コンテナ起動後も、使えるまでに時間がかかる。
- コードファーストで出力されたテーブルのDDLが大量に出力される。
まとめ
後編は、SQL Server と Oracle を使って、.NET 6 の Entity Framework Core を作成した場合、 どれくらい違いがでるのかを確認しました。
データベースの削除と作成は、本番環境のアプリに組み込むのは危険ですが、 単体テストに組み込むと、データベースの操作が不要になるので便利です。
また、異なるデータベース間の移行ツールを Entity Framework Core で作るのも 以前の方法で作るよりも、簡単に作れそうで興味深いです。
最後に参考サイトを掲載しておきます。
では、皆さん、よい旅を。