正しい姿勢?EF Coreで列挙型をこのように使う?

正しい姿勢?EF Coreで列挙型をこのように使う?

EntityFramework Coreのエンティティは列挙型の操作を直接サポートしていないため、開発過程で多くの問題が発生します。

最終更新 2021/11/09 10:06
waitaction
読了目安 2 分
カテゴリ
EF Core
タグ
.NET C# EF Core ORM .NET Core

EntityFramework Core ではエンティティが列挙型を直接サポートしていないため、開発時に多くの不便が生じます。以下に、ef core で列挙型を使用する方法をまとめます。

例えば、以下の MsgInfo エンティティはデータベーステーブル MsgInfo に対応しており、フィールド SendState(送信状態)はビジネスロジック上、送信成功送信失敗の2つの列挙状態を持ちます。しかし ef はこれを int 型として生成し、列挙型としては扱いません。もちろん列挙型に変更することもできません。変更すると ef のデータ書き込み・読み取りで異常が発生します。

元のエンティティ

public partial class MsgInfo
{
    public string Id { get; set; }
    public string UserAddress { get; set; }
    public string Content { get; set; }
    public int SendState { get; set; }
}

ここで新しいフィールド SendStateEnum を列挙型として追加し、[NotMapped] を付けてデータベースにマッピングしないようにします。また、HTTP 出力時にシリアライズされないようにするため、[Newtonsoft.Json.JsonIgnore] 属性を追加しても構いません。

NuGet パッケージ Newtonsoft.Json を追加する必要があります。

変更後のエンティティコードは以下の通りです。

エンティティの修正

public partial class MsgInfo
{
    public string Id { get; set; }
    public string UserAddress { get; set; }
    public string Content { get; set; }
    public int SendState { get; set; }

    [NotMapped]
    [Newtonsoft.Json.JsonIgnore]
    public SendStateEnum SendStateEnum
    {
        get
        {
            switch (SendState)
            {
                case (int)SendStateEnum.Fail:
                    return SendStateEnum.Fail;
                case (int)SendStateEnum.Success:
                    return SendStateEnum.Success;
                default:
                    return SendStateEnum.UnKnow;
            }
        }
        set
        {
            SendState = (int)value;
        }

    }
}
public enum SendStateEnum
{
    Success = 1,
    Fail = 2,
    UnKnow =3
}

SendStateEnum フィールドを追加した後は、ef core での操作や読み取り時に SendState フィールドの代わりに SendStateEnum を使用します(注:サイト管理者が実際に試したところ、原文とは異なります。以下のコード(原文のコード)は ef core の操作に SendState を使用すべきと思われます。異論があればコメントで指摘してください。

using (var context = new FrameworkDbContext())
{
    var result = context.MsgInfo.Where(m => m.SendStateEnum == SendStateEnum.Success);
}

もちろん、元の SendState フィールドが使用されないようにするため、[Obsolete] 属性を追加して、このフィールドが非推奨であることをユーザーに知らせることができます。

修正後の最終エンティティコード

public partial class MsgInfo
{
    public string Id { get; set; }
    public string UserAddress { get; set; }
    public string Content { get; set; }

    [Obsolete]
    public int SendState { get; set; }

    [NotMapped]
    [Newtonsoft.Json.JsonIgnore]
    public SendStateEnum SendStateEnum
    {
        get
        {
            switch (SendState)
            {
                case (int)SendStateEnum.Fail:
                    return SendStateEnum.Fail;
                case (int)SendStateEnum.Success:
                    return SendStateEnum.Success;
                default:
                    return SendStateEnum.UnKnow;
            }
        }
        set
        {
            SendState = (int)value;
        }
    }
}
public enum SendStateEnum
{
    Success = 1,
    Fail = 2,
    UnKnow =3
}
さらに探索

関連読書

その他の記事