Entity Frameworkで列挙体をメンバーとして持つEntityをコードファーストにて、テーブルを作成すると、列挙体部分は整数(int)型となる。列挙体中の並びに変更が無ければ問題にならないのだが、DBに値を保存した後で列挙体の順番が変更されてしまうと齟齬が発生する。
列挙体への項目挿入などの変更が考えられる場合には、DB中に列挙体メンバー名を文字列化して保存した方が良いかもしれない。
このような値変換を行うには、DbContextから派生させたクラスで、OnModelCreatingをオーバーライドして、Entity中のプロパティについて値コンバーターを定義すればよい。
// Alert Level
public enum AlertLevel { Debug, Information, Warning, Error, Fatal }
// Message
public class AlertMessage {
[Key]
public int MessaegId { get; set; }
public AlertLevel Level { get; set; }
public string Message { get; set; } = null!;
public DateTime LogDate { get; set; }
}
// DbContext
public class ConvTestCtx : DbContext {
public DbSet<AlertMessage> Messages { get; set; } = null!;
・・・
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder
.Entity<AlertMessage>()
.Property(e => e.Level)
.HasConversion(
v=>v.ToString(), // Instance⇒DB
v=>(AlertLevel)Enum.Parse(typeof(AlertLevel),v) // DB⇒Instance
);
}
}
これで、生成されるテーブル作成SQLは以下の通り。
CREATE TABLE [Messages] (
[MessaegId] int NOT NULL IDENTITY,
[Level] nvarchar(max) NOT NULL,
[Message] nvarchar(max) NOT NULL,
[LogDate] datetime2 NOT NULL,
CONSTRAINT [PK_Messages] PRIMARY KEY ([MessaegId])
);
ご覧のとおり、Levelがnvarchar(max)となっている。実際に登録した結果は以下の通り。
MessaegId Level Message LogDate 5 Information System has Started 2023/03/24 08:53:15 6 Warning Low Battery 2023/03/24 08:53:17 7 Debug Debug Message 2023/03/24 08:53:18
てな感じで、双方向の型変換が可能。