То, что вы ищете, может быть достигнуто путем установки необязательной ассоциации между 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.
Обновление:
Сначала давайте посмотрим, почему вышеупомянутый модульный тест прошел успешно, заглянув в SQL Profiler. Ниже показана трассировка сразу после вызова второго метода SaveChanges ():
Итак, как вы можете видеть, EF достаточно умен, чтобы сначала обновить гостевую запись, установив для ее LanguageID
значение NULL, а затем отправить инструкцию удаления для удаления языковой записи, которая является поведением EF по умолчанию, когда вы устанавливаете необязательный параметр. ассоциация. Таким образом, EF позаботилась об этом на стороне приложения, и, конечно, вы получите сообщение об ошибке от СУБД, если попытаетесь вручную удалить языковую запись внутри SQL Server, как вы также упоминали.
Тем не менее, это еще не все в этой истории. Рассмотрим следующий модульный тест:
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 , как вы можете увидеть его пример в * 1036. * этот пост . В вашем случае мы можем кодировать:
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");
}
Что вы ищете. При наличии вышеуказанного метода посева второй модульный тест также пройдет.
Надеюсь, это поможет,
Мортеза