Question

I'm getting the following InvalidOperationException:

The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.

This occurs when I run the following code (note where I call Clear() on the ShipDates collection and then add new instances):

// 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;

Here are the relevant parts of the two classes participating in the identifying relationship:

/// <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; }
}

And:

/// <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; }
}

The error occurs at SaveChanges() if I have an existing OrderPage that I'm modifying. I want the OrderPage to drop all existing OrderPageShipDates in the ShipDates collection and add back in new instances.

Can you help me figure this out? Thanks in advance.

Oh, re the response below - I am explicitly loading the ship dates in the GetOrder() call. Here's that code:

[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;
} 
Was it helpful?

Solution

Ok, I found the answer or answers.

First, I was trying to do too much before _context.SaveOrUpdate(). I needed to get the Id from the DB for my OrderPage before I added my OrderPageShipDates since their composite keys depend on the 'real' OrderPageId. So I call _context.SaveOrUpdate() before adding them now which gets me the 'real' Id.

Second, I had mis-implemented the _context.AddOrUpdate() logic. It was only doing an Add. Lot's of trickle down effects but the biggest was the Principal Id was changing (it was added again instead of being updated).

Thanks again for your efforts!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top