データベースの設計と運用はシステムエンジニアリングにおいて不可欠な要素ですが、特に複数のアプリケーションで共有されるデータベースの一貫性と効率的な管理は大きな課題となります。今回の記事では、Entity Framework Coreを活用して、Visual Studio 2022とOracle 21cを用いたコードファーストのアプローチでデータベーステーブルを生成し、複数のアプリケーション間で共通のデータアクセスレイヤーを構築する方法をご紹介します。この方法により、開発の柔軟性が高まり、システム全体の効率と品質が向上することが期待されます。
はじめに
やりたいこと
テーブルはコードファーストで作成したい。
DBに接続するDLLを複数アプリで共通で利用できるものにしたい。
前提
VisualStudio2022インストール済
Oracle21Cはインストール済み(MY211、MY212でスキーマを作成)
Entity Framework Coreのセットアップ
- Visual Studio 2022を開き、新しいプロジェクト(Class Library (.NET Core))を作成する。
- プロジェクトにNuGetパッケージマネージャーから必要なパッケージをインストールする。
※パッケージ※
Microsoft.EntityFrameworkCore
Oracle.EntityFrameworkCore
Microsoft.EntityFrameworkCore.Tools
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.Json
Microsoft.Extensions.Configuration.Binder - フォルダ構成
📁 Sample.EntityFramework ├─ 📁 DbDefinitions │ ├─ 📁 MY211 │ │ ├─ 📁 Entities │ │ │ └─ 📄 MyTables.cs │ │ └─ 📄 MY211DbContext.cs │ ├─ 📁 MY211_Migration │ │ └─ 📄 MY211_MigrationDbContext.cs │ ├─ 📁 MY212 │ │ ├─ 📁 Entities │ │ │ └─ 📄 SampleTable.cs │ │ └─ 📄 MY212DbContext.cs │ └─ 📁 MY212_Migration │ └─ 📄 MY212_MigrationDbContext.cs ├─ 📄 appsettings.json └─ 📄 ConfigurationHelper.csせ
設定ファイルの作成
appsettings.json
※Oracle21cのコンテナはデフォルトの「XEPDB1」とし、その中にユーザ[MY211][MY212]を作成
{ "ConnectionStrings": { "MY211DbConnection": "User Id=MY211;Password=MY211;Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=DESKTOP-OC26K7E)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XEPDB1)));", "MY212DbConnection": "User Id=MY212;Password=MY212;Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=DESKTOP-OC26K7E)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XEPDB1)));" }, }
ConfigurationHelper.cs
using Microsoft.Extensions.Configuration; namespace Sample.EntityFramework { public class ConfigurationHelper { public static IConfigurationRoot GetConfiguration(string basePath, string appSettings = "appsettings.json") { return new ConfigurationBuilder() .SetBasePath(basePath) .AddJsonFile(appSettings, optional: false, reloadOnChange: true) .Build(); } } }
DbContextクラスの作成:
MY211DbContext.cs
using Microsoft.EntityFrameworkCore; using Sample.EntityFramework.DbDefinitions.MY211.Entities; namespace Sample.EntityFramework.DbDefinitions.MY211 { public class MY211DbContext : DbContext { protected MY211DbContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); } // 他プロジェクトから読み込み用 // 読み込み方法 // var context = new MY211DbContext(); public MY211DbContext() : base(GetOptions()) { } private static DbContextOptions GetOptions() { var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .Build(); var connectionString = configuration.GetConnectionString("MY211DbConnection"); var optionsBuilder = new DbContextOptionsBuilder(); optionsBuilder.UseOracle(connectionString); return optionsBuilder.Options; } // テーブルを定義 public DbSet MyTable { get; set; } } }
MY211_MigrationDbContext
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; using Sample.EntityFramework.DbDefinitions.MY211; namespace Sample.EntityFramework.DbDefinitions.MY211_Migration { public class MY211_MigrationDbContextFactory : IDesignTimeDbContextFactory { public MY211_MigrationDbContext CreateDbContext(string[] args) { // 設定ファイルの読み込み var configuration = ConfigurationHelper.GetConfiguration(Directory.GetCurrentDirectory()); // 接続文字列の取得 var connectionString = configuration.GetConnectionString("MY211DbConnection"); // DbContextOptionsを構成 var optionsBuilder = new DbContextOptionsBuilder(); optionsBuilder.UseOracle(connectionString); return new MY211_MigrationDbContext(optionsBuilder.Options); } } public class MY211_MigrationDbContext : MY211DbContext { public MY211_MigrationDbContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.HasDefaultSchema("MY211"); } } }
MY212DbContext
using Microsoft.EntityFrameworkCore; using Sample.EntityFramework.DbDefinitions.MY212.Entities; namespace Sample.EntityFramework.DbDefinitions.MY212 { public class MY212DbContext : DbContext { protected MY212DbContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); } public DbSet SampleTable { get; set; } } }
MY212_MigrationDbContext
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; using Microsoft.Extensions.Configuration; using Sample.EntityFramework.DbDefinitions.MY212; namespace Sample.EntityFramework.DbDefinitions.MY212_Migration { public class MY212_MigrationDbContextFactory : IDesignTimeDbContextFactory { public MY212_MigrationDbContext CreateDbContext(string[] args) { // 設定ファイルの読み込み var configuration = ConfigurationHelper.GetConfiguration(Directory.GetCurrentDirectory()); // 接続文字列の取得 var connectionString = configuration.GetConnectionString("MY212DbConnection"); // DbContextOptionsを構成 var optionsBuilder = new DbContextOptionsBuilder(); optionsBuilder.UseOracle(connectionString); return new MY212_MigrationDbContext(optionsBuilder.Options); } } public class MY212_MigrationDbContext : MY212DbContext { public MY212_MigrationDbContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.HasDefaultSchema("MY212"); } } }
モデルクラスの定義
MyTable.cs
using System.ComponentModel.DataAnnotations; namespace Sample.EntityFramework.DbDefinitions.MY211.Entities { public class MyTable { public int Id { get; set; } [MaxLength(100)] public string? Name { get; set; } [MaxLength(2000)] public string? Description { get; set; } [MaxLength(11)] public string? tel { get; set; } } }
SampleTable.cs
using System.ComponentModel.DataAnnotations; namespace Sample.EntityFramework.DbDefinitions.MY212.Entities { public class SampleTable { public int Id { get; set; } [MaxLength(100)] public string? Name { get; set; } } }
マイグレーション実施
addのあとの「yyyymmdd_name」はマイグレーションの履歴ファイルになります。
被らないようにする必要があるので、マイグレーションの年月日などで管理します。
MY211スキーマ用
// 追加 dotnet ef migrations add yyyymmdd_name --project Sample.EntityFramework\Sample.EntityFramework.csproj --context Sample.EntityFramework.DbDefinitions.MY211_Migration.MY211_MigrationDbContext -o DbDefinitions\MY211_Migration // 更新 dotnet ef database update --project Sample.EntityFramework\Sample.EntityFramework.csproj --context Sample.EntityFramework.DbDefinitions.MY211_Migration.MY211_MigrationDbContext
MY212スキーマ用
// 追加 dotnet ef migrations add yyyymmdd_name --project Sample.EntityFramework\Sample.EntityFramework.csproj --context Sample.EntityFramework.DbDefinitions.MY212_Migration.MY212_MigrationDbContext -o DbDefinitions\MY212_Migration // 更新 dotnet ef database update --project Sample.EntityFramework\Sample.EntityFramework.csproj --context Sample.EntityFramework.DbDefinitions.MY212_Migration.MY212_MigrationDbContext
※DBに初回であれば【__EFMigrationsHistory】、定義したテーブルが作成されていることを確認する。
まとめ
今回は、同じDBに別スキーマを作成して、それぞれに対してのマイグレーションを同じプロジェクトでできる構成を作成してみました。別DBでも同じ要領でできるのかなと思っています。
これでビルドしてDLLが作成されるのでLinqPadなどで読み込めだLinqPadでDB操作が容易に行えるようになりました!
コメント