lycheejam's tech log

チラ裏のメモ帳 | プログラミングは苦手、インフラが得意なつもり。

C# EntityFrameworkでIDENTITY属性を無効化する

概要

EntityFrameworkではCodeFirstでDBを操作する際、主キーに対して自動でインクリメントのINDEXが付与される(IDENTITY属性)
キーを任意の数字としたかったので無効化した。

環境

Model(オブジェクト)

海上自衛隊護衛艦の艦船情報です。

class SelfDefenseShip { //護衛艦
    public virtual EscortDivision EscortDivision { get; set; }  //所属
    public virtual HullCode HullCode { get; set; }  //艦種記号
    [Key]
    [Required]
    public int ShipNumber { get; set; }     //艦識別番号
    public string ShipName { get; set; }    //艦名
    public virtual ShipClass ShipClass { get; set; }    //艦種型
    public int StandardDisplacement { get; set; }   //基準排水量(トン)
    public int FullLoadDisplacement { get; set; }   //満載排水量(トン)
    public double FullLength { get; set; }  //全長(メートル)
    public double FullWidth { get; set; }   //全幅(メートル)
    public DateTime CommissionYear { get; set; } //就役(年)
}

他に参照しているモデルがありますが、今回は関係ないので無視します。
キーとして艦識別番号を指定しています。

140725-N-FC670-2229

※こちらの写真が格好よかったので掲載していたのですが著作権的にNGなのでURLのみ記載しておきます。

画像にあるような船首の番号です。

艦情報のインサート

public void InsertShipData() {
    using (var db = new ShipsDbContext()) {
        using (var sr = new StreamReader(@"..\..\Data\ShipData.txt")) {
            var tmp = sr.ReadToEnd().Split(new string[] { "\r\n" }, StringSplitOptions.None);

            for (int i = 0; i < tmp.Length; i++) {
                var sdstmp = tmp[i].Split(new string[] { "\t" }, StringSplitOptions.None);
                //...中略

                var sds = new SelfDefenseShip {
                    ShipNumber = Int32.Parse(sdstmp[2]),  //艦番号
                    ShipName = sdstmp[3]  //艦名
                    //...中略
                };
                db.SelfDefenseShips.Add(sds);   //データをインサート
            }
            db.SaveChanges();   //DBコミット
        }
    }
}

用意した艦船情報を読み込みデータを追加します。

var sds = new SelfDefenseShip {
    ShipNumber = Int32.Parse(sdstmp[2]),  //艦番号
    ShipName = sdstmp[3]  //艦名
    //...中略
};

ShipNumberを主キーとするため艦船識別番号を格納しています。

IDENTITY属性が付与されている場合

ShipNumberに対して[Key]のアノテーションのみ付けている場合です。

f:id:HM_Atlas:20180501195130p:plainf:id:HM_Atlas:20180501195140p:plain

インサート時に艦船番号を格納していますが、艦船番号がインクリメントされています。
問題点は以下のSQLです。

[ShipNumber] INT IDENTITY (1, 1) NOT NULL

自動でIDENTITY属性が付与されておりカウントアップされているようです。

IDENTITY属性を無効化した場合

モデルに対してアノテーションを付与します。

class SelfDefenseShip { //護衛艦
    //...省略
    [Key]
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int ShipNumber { get; set; }     //艦識別番号
    //...省略
}

DatabaseGenerated属性のDatabaseGeneratedOptionを指定することによって
IDENTITY属性の振る舞いを指定することが出来ます。

今回は任意の値を指定したいのでnoneを指定します。

f:id:HM_Atlas:20180501200611p:plainf:id:HM_Atlas:20180501200530p:plain

SQLからIDENTITY属性が消されました。

[ShipNumber] INT NOT NULL

データにも任意の艦船番号が入っており
こちらの意図した通りの動きとなっています。

雑感

正直艦船番号が飛んでたりするので主キーとして採用するのはいかがなものかって感じですね。
恐らく重複は無いはず。