我正在使用EF4 CTP 5,CodeFirst。
请先看我的课程:
public class Guest
{
[Key]
public Guid GuestID { get; set; }
public Language PreferredLanguage { get; set; }
public Guid? LanguageID { get; set; }
}
public class Language
{
[Key]
public Guid LanguageID { get; set; }
[Required(ErrorMessage = "Enter language name")]
[StringLength(50, ErrorMessage = "Language name is too long")]
public string LanguageName { get; set; } // in origine language
}
我的目标是为访客语言关系设置一定的“删除规则”。删除语言后,我不希望删除相应的guest虚拟机(因此 NO 级联删除)。相反,我希望客人的LanguageID为“Set NULL”。
我希望流利的API在这里支持我。但我找不到任何有用的东西.WillCascadeOnDelete(bool),它不提供我需要的选项。我错过了什么吗?或者这只是在CTP 5中没有实现?
感谢您的帮助!
答案 0 :(得分:34)
您可以通过在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事件探查器而成功。下面显示了调用第二个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获得的确切消息。原因是因为在第二个单元测试中我们没有在上下文中加载相关的guest对象,因此EF不知道它并且不会像在第一个示例中那样提交必要的更新语句。
回到你的问题,遗憾的是EF Code First不允许显式更改关系上的删除/更新规则,但我们总是可以使用 SqlCommand 方法,因为你在{{3}中看到了它的示例}。在您的情况下,我们可以编码:
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");
}
您正在寻找的是什么。如果采用上述种子方法,第二次单元测试也将通过。
希望这有帮助,
Morteza
答案 1 :(得分:0)
使用Entity Framework Core,我做了类似的事情......
modelBuilder.Entity<Guest>()
.HasOne(g => g.Language)
.WithMany(l => l.Guests) // I needed a return collection
.OnDelete(DeleteBehavior.SetNull);