您正在寻找的可以通过在和实体之间设置可选关联来实现: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 空值的记录。
更新:
首先让我们通过查看 SQL Profiler 来看看为什么上面的单元测试会成功。下面显示了调用第二个 SaveChanges() 方法后的跟踪:
如您所见,EF 非常聪明,可以先通过将访客记录设置LanguageID
为 null 来更新访客记录,然后提交删除语句来删除语言记录,这是您设置可选关联时的默认 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();
}
这个失败并抛出 SQLException 包含您在尝试手动删除记录时从 SQL Server 获得的确切消息。这样做的原因是因为在第二个单元测试中,我们没有在上下文中加载相关的来宾对象,因此 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");
}
这就是你要找的。有了上述种子方法,第二个单元测试也将通过。
希望这会有所帮助,
莫特萨