3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

EF Coreでシーケンスを用いたId以外の列の自動採番を行う

Last updated at Posted at 2025-03-12

前提・目的

  • EF Coreを使った新規登録を行う。
  • SQL Serverを利用。
  • こんなテーブル
CREATE TABLE [dbo].[MyTableSample1](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[SubId] [nvarchar](10) NOT NULL,
	[Name] [nvarchar](50) NULL
)
  • Id 以外にSubIdというvarchar(10)の列があり、新規登録時にはシーケンスを参照して自動採番をしたい。

手順

SQL Server側の設定

シーケンスの生成

CREATE SEQUENCE [dbo].[MyTable1SubId1_SEQ] 
 AS [int]
 START WITH 1
 INCREMENT BY 1

シーケンス名は適当に。

SubIdにDEFAULT制約を指定し、シーケンスを参照させる

ALTER TABLE [dbo].[MyTableSample1] ADD  CONSTRAINT [DF_MyTableSample1_SubId]  
DEFAULT (NEXT VALUE FOR [MyTable1SubId1_SEQ]) FOR [SubId]

これによって、INSERT時にSubIdnullなら自動的にシーケンスのNEXT VALUEを取ってきて設定してくれる。

EF Core側の設定

DbContextのOnModelCreatingに以下のように追記

HasDefaultValueSql()SubIdプロパティに対して設定する。

modelBuilder.Entity<MyTableSample1>(entity =>
{
    entity.HasKey(e => e.Id).HasName("PK_MyTableSample1");
    entity.ToTable("MyTableSample1");
    entity.Property(e => e.SubId)
        .IsRequired()
+       .HasDefaultValueSql();

    entity.Property(e => e.Name)
        .IsRequired()
        .HasMaxLength(50);
});

HasDefaultValueSql()を付けることでこのフィールドにDEFAULT制約があることを明示する。これによってEF CoreによるINSERT時にこのフィールドがnullであっても例外を上げなくなる。

このHasDefaultValueSql()は、そのまま空の引数でもよいが、できれば実際のDEFAULT制約の指定値を設定しておく方が良い。

        .HasDefaultValueSql("(NEXT VALUE FOR [MyTable1SubId1_SEQ])");

こうすることで、Code FirstによるDB生成時に自動的にDEFAULT制約を付与してくれる。

勘違いしやすいが、上記のように指定すれば、INSERT時に自動的に規定値が設定されるわけではない(最初勘違いしてドはまりした。ネット上にも勘違いしていると思われる記事が見られ、Copilotも嘘情報を教えてくる)。この引数にはあくまでもCode First時の参照情報としての役割しかないようで、例えば"test"のような適当な値を設定しても何もエラーは起きない。

新規登録コードのサンプル

var entitiy = new MyTableSample1
{
    Name = "テスト",
};
db.Add(entitiy);
await db.SaveChangesAsync();
// SaveChanges後、EF Coreによってentity.Id と entity.SubId には新しい値が設定される

上記のコメントにもあるように、SaveChanges()の後、entity.Identity.SubIdには自動的に採番された値が設定される。

これはEF Core内部ではSQLのOUTPUT句を用いて実現されている。
さすがEF Core、便利なことこの上ない。

EF Coreが発行するINSERT文
  SET NOCOUNT ON;
  INSERT INTO [MyTableSample1] ([Name])
  OUTPUT INSERTED.[Id], INSERTED.[SubId] -- この行によってIdとSubIdが返される
  VALUES (@p0);

あとがき

SubIdの型がvarchar(10)なのはわざとで、intにしない場合どうなるのかなと思ったが問題なく文字列として数値が設定された。

記事中にも書いたが、最初HasDefaultValueSqlを指定することでINSERT時にデフォルト値が適用されるようになるよ、というような事をCopilotが言い出して、ホンマかと思ってやってみたら普通に「null非許容フィールドにnullを設定しようとしました」みたいなエラーが出て「なんでや!?」と思って公式サイトを見に行くも、確かにそのような話が書かれており…。

しかしここで「これひょっとしてCode First前提なのでは」と思い当たり、そこから調べた結果、どうやらそうらしいということで、同じ事でハマってる人の救いになればと記事に残しておきます。

参考

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?