Entity Framework 5 Идентификация отношений с использованием кода Сначала генерируется исключение InvalidOperationException
Я получаю следующее InvalidOperationException:
Изменения в базе данных были успешно зафиксированы, но при обновлении контекста объекта произошла ошибка. ObjectContext может быть в несовместимом состоянии. Внутреннее сообщение об исключении: Произошло нарушение ограничения ссылочной целостности: Значения свойств, которые определяют ссылочные ограничения, не согласованы между основным и зависимыми объектами в отношении.
Это происходит, когда я запускаю следующий код (обратите внимание, где я вызываю Clear() для коллекции ShipDates, а затем добавляю новые экземпляры):
// get or create the order
Order order = null;
if (vm.OrderNumber > 0)
order = GetOrder(vm.OrderNumber);
else
order = new Order(orderDate: DateTime.Now, isClosed: false, brokerNum: broker.BrokerNumber);
// get or create the order page
OrderPage orderPage = null;
bool bIsExistingPage = vm.PageNumber > 0;
if (bIsExistingPage)
orderPage = order.OrderPages.First(op => op.PageNumber == vm.PageNumber);
else
orderPage = new OrderPage(vm.VendorNumber, vm.BulletinNumber, 1, DateTime.Now, order);
// merge changes or create the order page items
foreach (var opi in vm.OrderPageItems)
{
var orderPageItem = orderPage.OrderPageItems.FirstOrDefault(xopi =>
xopi.StoreNumber == opi.StoreNumber &&
xopi.ItemNumber == opi.ItemNumber);
if (orderPageItem == null)
{
orderPageItem = new OrderPageItem(
vendorNum: vm.VendorNumber,
bullNum: vm.BulletinNumber,
itemNum: opi.ItemNumber,
storeNum: opi.StoreNumber,
quantity: opi.Quantity,
orderPage: orderPage);
orderPage.OrderPageItems.Add(orderPageItem);
}
else
{
orderPageItem.Quantity = opi.Quantity;
}
}
// clear out the old ship dates if any
orderPage.ShipDates.Clear();
// reset the ship dates
vm.ShipDates.ForEach(date => orderPage.ShipDates.Add(new OrderPageShipDate(date, orderPage)));
if (!bIsExistingPage)
order.OrderPages.Add(orderPage);
_context.AddOrUpdate(order);
_context.SaveChanges();
result.OrderNumber = order.OrderNumber;
result.OrderDate = order.OrderDate;
Вот соответствующие части двух классов, участвующих в идентификации отношений:
/// <summary>
/// This class represents a a set of items added to an order from a particular bulletin at a particular time.
/// </summary>
[ScaffoldTable(true)]
public class OrderPage : IEntity, IAuditInfo
{
#region Construction
//...
#endregion
#region IEntity Members
/// <summary>
/// The unique identifier for an order item.
/// </summary>
[Key]
public virtual int Id { get; set; }
#endregion
// other properties...
public virtual ICollection<OrderPageShipDate> ShipDates { get; private set; }
}
А также:
/// <summary>
/// This class represents a shipping date for an order page that has been added to an order.
/// </summary>
[ScaffoldTable(true)]
public class OrderPageShipDate : IEntity
{
#region Construction
// ...
#endregion
#region IEntity Members
/// <summary>
/// The unique identifier for an order item.
/// </summary>
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), Column(Order = 2)]
public virtual int Id { get; set; }
#endregion
public virtual DateTime ShipDate { get; private set; }
[Key, ForeignKey("OrderPage"), Column(Order = 1)]
public virtual int OrderPageId { get; private set; }
public virtual OrderPage OrderPage { get; private set; }
}
Ошибка возникает в SaveChanges(), если у меня есть существующий OrderPage, который я изменяю. Я хочу, чтобы OrderPage отбрасывал все существующие OrderPageShipDates в коллекции ShipDates и добавлял их обратно в новых экземплярах.
Можете ли вы помочь мне понять это? Заранее спасибо.
О, ответ ниже - я явно загружаю даты доставки в вызове GetOrder(). Вот этот код:
[NonAction]
private Order GetOrder(int orderNumber)
{
var user = _context.Users.SingleOrDefault(u => u.Username == User.Identity.Name);
var roles = _roleProvider.GetRolesForUser(User.Identity.Name).ToList();
var broker = user as Broker;
order = _context.Orders
.Where(o => o.BrokerNumber == broker.BrokerNumber && o.OrderNumber == orderNumber)
.Include(o => o.OrderPages)
.Include(o => o.OrderPages.Select(op => op.OrderPageItems))
.Include(o => o.OrderPages.Select(op => op.ShipDates))
.SingleOrDefault();
return order;
}
1 ответ
Хорошо, я нашел ответ или ответы.
Во-первых, я пытался сделать слишком много, прежде чем _context.SaveOrUpdate()
, Мне нужно было получить идентификатор из БД для моего OrderPage
прежде чем я добавил свой OrderPageShipDate
s, поскольку их составные ключи зависят от "реального" OrderPageId
, Так я звоню _context.SaveOrUpdate()
прежде чем добавить их сейчас, что дает мне "реальный" Id.
Во-вторых, я неправильно реализовал _context.AddOrUpdate()
логика. Он делал только Add. Многие эффекты просачивались, но самым большим было изменение основного идентификатора (он был добавлен снова, а не обновлен).
Еще раз спасибо за ваши усилия!