Необходимо убедиться, что ссылка на бронирование в сообщении указывает на тот же экземпляр, что и добавляемое вами бронирование. EF будет управлять ассоциацией FK оттуда.
Например:
bvm.Messages.Booking = bvm.Booking; // Associate the same reference.
_context.Booking.Add(bvm.Booking);
_context.Messages.Add(bvm.Messages);
_context.SaveChanges();
Я бы не стал передавать классы Entity в модель представления, так как это может привести к всевозможным проблемам, так как вы можете подумать, что вы передаете объект, но на самом деле вы просто передаете экземпляр POCO-данных, который не связан с контекст. EF будет обрабатывать каждый десериализованный экземпляр как новую ссылку, даже если у них совпадают идентификаторы. Вы должны связать их с DbContext и обновить ссылки на экземпляры, которые уже могут быть связаны. Это уродливо, подвержено ошибкам, а также склонно к несанкционированному манипулированию данными со стороны злоумышленников.
Например: возьмите сценарий, который принимает следующие данные:
Booking { Id = 0 }, Message { Id = 0, Booking { Id = 0 }}
Таким образом, он принимает новое бронирование с идентификатором 0 и новое сообщение со ссылкой на наше новое бронирование.
Когда мы позвоним context.Booking.Add(booking)
EF создаст новое бронирование с автоматически сгенерированным идентификатором. Скажем «15». Когда оно доходит до сообщения, сообщение содержит новую, другую ссылку на бронирование, поэтому EF отправляет и вставляет его и получает Id 16. (Хотя остальные данные о бронировании идентичны первым переданным в) Поскольку две ссылки на бронирование не указывают на один и тот же экземпляр, EF также рассматривает их как два совершенно разных экземпляра. При установке ссылки на бронирование для сообщения на первый в нашем методе, когда EF обновляет бронирование, ссылка на бронирование сообщения будет указывать на идентификатор этого первого.
Чтобы избежать подобных уродств, мы хотим избежать повторяющихся ссылок. Если у нас есть метод, который вставляет новое бронирование с необязательным сообщением, то вместо передачи сущностей, которые создают проблемы, подобные этой, передайте обычные модели представления C # и затем обработайте создание (или загрузку) сущности на сервере. Объекты, передаваемые в такие методы, по сути являются просто классами POCO, но они содержат намного больше данных, чем вы не должны «доверять» обновлению в базе данных. Передавая отдельную модель представления, мы применяем лучшие методы:
Загрузка существующих ссылок на сущности из текущего DBContext и / или создание и связывание сущностей на основе предоставленных данных.
Таким образом, метод, который создает новое бронирование с дополнительным сообщением, может выглядеть так:
public ActionResult AddBooking(BookingViewModel booking, MessageViewModel message)
{
var newBooking = new Booking { BookedDate = booking.BookedDate, /* ... */ };
_context.Bookings.Add(newBooking);
if (message != null)
{
var newMessage = new Message { MessageText = message.Text, Booking = newBooking };
_context.Messages.Add(newMessage);
}
_context.SaveChanges();
}
Еще лучше было бы, чтобы у объекта бронирования была коллекция сообщений. Я подозреваю, что вы, вероятно, попробовали это изначально, но столкнулись с проблемами сериализации при попытке передать заказы клиенту. (Еще одна причина не пропускать сущности)
public ActionResult AddBooking(BookingViewModel booking, MessageViewModel message)
{
var newBooking = new Booking { BookedDate = booking.BookedDate, /* ... */ };
if (message != null)
{
var newMessage = new Message { MessageText = message.Text, Booking = newBooking };
newBooking.Messages.Add(newMessage);
}
_context.Bookings.Add(newBooking);
_context.SaveChanges();
}
Это усиливает отношения между сущностями, так что контекст не должен рассматривать каждую сущность как сущность верхнего уровня. Когда бронирование сохранено, его сообщения также будут сохранены, и ссылки FK будут заполнены автоматически.
По мере того, как вы будете входить в сценарии редактирования и тому подобное, продолжение передачи ссылок на сущности приведет к еще большему затруднению с дублирующимися данными и ошибкам контекста для сущностей с совпадающими идентификаторами, которые уже отслеживаются. Это не стоит путаницы. :)