Убедитесь, что OrderDetails связаны с контекстом, в котором создается заказ. Типичная причина - детали заказа загружаются в другом контексте, возможно, десериализованы из веб-запроса и связаны с новым заказом. Проблема в том, что экземпляр контекста, сохраняющий заказы, не распознает эти OrderDetails и обрабатывает их как новые (добавленные) сущности.
Приведенный в качестве примера метод, подобный этому:
public Order CreateOrder(IEnumerable<OrderDetail> orderDetails)
{
using (var context = new AppContext())
{
var order = new Order();
order.OrderDetails.AddRange(orderDetails);
context.Orders.Add(order);
context.SaveChanges();
return order;
}
}
Произошла ошибкапотому что контекст выше не знает о OrderDetails. Добавление объектов в новый порядок рассматривается как добавление новых OrderDetails, приводящих к нарушениям PK, или вставка дубликатов с новыми идентификаторами, если генерируются PK.
Вариант 1. При создании нового объекта обязательно загрузите все связанные объекты. Вместо передачи сущностей для ассоциаций вы можете сэкономить пропускную способность, передав идентификаторы:
public Order CreateOrder(IEnumerable<int> orderDetailIds)
{
using (var context = new AppContext())
{
var order = new Order();
var orderDetails = context.OrderDetails.Where(x => orderDetailIds.Contains(x.OrderDetailId)).ToList();
order.OrderDetails.AddRange(orderDetails);
context.Orders.Add(order);
context.SaveChanges();
return order;
}
}
Это гарантирует, что детали заказа известны контексту и связаны с новым заказом, а не рассматриваются как новые записи.
Вариант 2. Связывание сущностей с контекстом
public Order CreateOrder(IEnumerable<OrderDetail> orderDetails)
{
using (var context = new AppContext())
{
var order = new Order();
foreach(var orderDetail in orderDetails)
{
context.OrderDetails.Attach(orderDetail);
}
order.OrderDetails.AddRange(orderDetails);
context.Orders.Add(order);
context.SaveChanges();
return order;
}
}
Эта опция связывает детали заказа с контекстом, прикрепляя их. Это может работать нормально, когда DbContext находится в области действия метода, и при условии, что все присоединяемые ссылки уникальны (без удвоений). При более длительных вызовах вы должны быть осторожны, если существует вероятность того, что объект уже был присоединен или иным образом загружен контекстом, в котором вызов Attach может завершиться неудачно. Присоединение сущностей, поступающих из веб-клиента, также не должно быть доверенным, поэтому вы должны убедиться, что состояние сущности никогда не будет изменено или это откроет дверь для сохранения поврежденных данных с помощью вызова SaveChanges.
Существуют гибридные опции, которые могут проверять локальный кеш на наличие ссылок и создавать заглушки, которые я собирался обрисовать, но они действительно подходят только для массовых операций и сопряжены со значительными рисками.