探しているものは、とエンティティ間のオプションの関連付けを設定することで実現できます。Guest
Language
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Guest>()
.HasOptional(p => p.PreferredLanguage)
.WithMany()
.HasForeignKey(p => p.LanguageID);
}
単体テスト:
using (var context = new Context())
{
var language = new Language()
{
LanguageName = "en"
};
var guest = new Guest()
{
PreferredLanguage = language
};
context.Guests.Add(guest);
context.SaveChanges();
context.Languages.Remove(language);
context.SaveChanges();
}
その結果、guest
LanguageID FK 列の DB null 値を持つレコードが作成されます。
アップデート:
まず、SQL プロファイラーを調べて、上記の単体テストが成功した理由を見てみましょう。以下は、2 番目の SaveChanges() メソッドを呼び出した直後のトレースを示しています。

ご覧のとおり、EF は十分に賢く、最初にゲスト レコードLanguageID
を null に設定して更新し、delete ステートメントを送信して言語レコードを削除します。これは、オプションの関連付けを設定するときの既定の EF の動作です。したがって、EFによってアプリケーション側で処理されています。もちろん、SQL Server内の言語レコードを手動で削除しようとすると、DBMSからエラーが発生します。
ただし、この話には続きがあります。次の単体テストを検討してください。
using (var context = new Context())
{
var language = new Language() { LanguageName = "en" };
var guest = new Guest() { PreferredLanguage = language };
context.Guests.Add(guest);
context.SaveChanges();
}
using (var context = new Context())
{
var language = context.Languages.First();
context.Languages.Remove(language);
context.SaveChanges();
}
これは、レコードを手動で削除しようとしたときに SQL Server から取得した正確なメッセージを含む SQLException をスローして失敗します。その理由は、2 番目の単体テストでは関連するゲスト オブジェクトがコンテキストに読み込まれていないため、EF はそれを認識せず、最初の例のように必要な更新ステートメントを送信しないためです。
ご質問に戻りますが、残念ながら EF Code First ではリレーションシップの削除/更新ルールを明示的に変更することはできませんが、この投稿で例を示しているように、いつでもSqlCommandメソッドに頼ることができます。あなたの場合、次のようにコーディングできます。
protected override void Seed(Context context)
{
context.Database.SqlCommand("ALTER TABLE dbo.Guests DROP CONSTRAINT Guest_PreferredLanguage");
context.Database.SqlCommand("ALTER TABLE dbo.Guests ADD CONSTRAINT Guest_PreferredLanguage FOREIGN KEY (LanguageID) REFERENCES dbo.Languages(LanguageID) ON UPDATE NO ACTION ON DELETE SET NULL");
}
これはあなたが探しているものです。上記のシード メソッドを配置すると、2 番目の単体テストもパスします。
これが役に立てば幸いです、
モルテザ