前提・目的
- 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時にSubId
がnull
なら自動的にシーケンスの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.Id
とentity.SubId
には自動的に採番された値が設定される。
これはEF Core内部ではSQLのOUTPUT句を用いて実現されている。
さすがEF Core、便利なことこの上ない。
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前提なのでは」と思い当たり、そこから調べた結果、どうやらそうらしいということで、同じ事でハマってる人の救いになればと記事に残しておきます。
参考