Ответ 1
То, что вы ищете, может быть достигнуто путем настройки необязательной связи между объектами Guest
и Language
:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Guest>()
.HasOptional(p => p.PreferredLanguage)
.WithMany()
.HasForeignKey(p => p.LanguageID);
}
Unit Test:
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
с нулевым значением DB для столбца FK LanguageID.
Обновление:
Сначала давайте посмотрим, почему предыдущему Unit Test удалось найти в SQL Profiler. Ниже показано трассирование сразу после вызова второго метода SaveChanges():
Итак, как вы можете видеть, EF достаточно умен, чтобы сначала обновить гостевую запись, установив ее LanguageID
в null, а затем отправить выражение на удаление, чтобы удалить запись языка, которая является поведением EF по умолчанию, когда вы настраиваете необязательный ассоциация. Таким образом, он был рассмотрен на стороне приложения EF и, конечно, вы получите сообщение об ошибке из СУБД, если вы попытаетесь вручную удалить языковые записи внутри SQL Server, как вы упомянули.
Тем не менее, в этой истории больше. Рассмотрим следующий unit test:
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 при попытке вручную удалить запись. Причина этого заключается в том, что во втором Unit Test у нас нет связанного объекта-гостя, загруженного в контекст, чтобы 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");
}
Это то, что вы ищете. При наличии вышеуказанного метода семени также пройдет второй Unit Test.
Надеюсь, это поможет,
Мортеза