2

I have not been working in SQL too long, but I thought I understood that by wrapping SQL statements inside a transaction, all the statements completed, or none of them did. Here is my problem. I have an order object that has a lineitem collection. The line items are related on order.OrderId. I have verified that all the Ids are set and are correct but when I try to save (insert) the order I am getting The INSERT statement conflicted with the FOREIGN KEY constraint "FK_OrderItemDetail_Order". The conflict occurred in database "MyData", table "dbo.Order", column 'OrderId'.

psuedo code:

create a transaction
transaction.Begin()
Insert order
Insert order.LineItems <-- error occurs here
transaction.Commit

actual code:

...
entity.Validate();
if (entity.IsValid)
{
    SetChangedProperties(entity);
    entity.Install.NagsInstallHours = entity.TotalNagsHours;
    foreach (OrderItemDetail orderItemDetail in entity.OrderItemDetailCollection)
    {
        SetChangedOrderItemDetailProperties(orderItemDetail);
    }
    ValidateRequiredProperties(entity);
    TransactionManager transactionManager = DataRepository.Provider.CreateTransaction();
    EntityState originalEntityState = entity.EntityState;
    try
    {
        entity.OrderVehicle.OrderId = entity.OrderId;
        entity.Install.OrderId = entity.OrderId;
        transactionManager.BeginTransaction();

        SaveInsuranceInformation(transactionManager, entity);
        DataRepository.OrderProvider.Save(transactionManager, entity);
        DataRepository.OrderItemDetailProvider.Save(transactionManager, entity.OrderItemDetailCollection);             if (!entity.OrderVehicle.IsEmpty)
        {
            DataRepository.OrderVehicleProvider.Save(transactionManager, entity.OrderVehicle);
        }
        transactionManager.Commit();
    }
    catch
    {
        if (transactionManager.IsOpen)
        {
            transactionManager.Rollback();
        }
        entity.EntityState = originalEntityState;
    }
}
...

Someone suggested I need to use two transactions, one for the order, and one for the line items, but I am reasonably sure that is wrong. But I've been fighting this for over a day now and I need to resolve it so I can move on even if that means using a bad work around. Am I maybe just doing something stupid?

jac
  • 9,666
  • 2
  • 34
  • 63
  • Seeing the description above it seems that your order ID is not autogenerated. If it is autogenerated then when you fire the fisrt SQL query at that time you will get the order ID which you need to set in order lines for the second query to be successful. – Kalpak Nov 03 '09 at 15:50
  • can you post the complete code? In the first ADO.NET there was no "ambient transaction" and you were required to pass the transaction object reference on every operation as parameter. If you miss this, the behavior you describe is common. – Marc Wittke Nov 03 '09 at 15:51
  • In a transaction everything occurs or they do not, but the operations still occur one after another. Make sure all your SQL commands are passed the same transaction. – Min Nov 03 '09 at 16:08

6 Answers6

1

Without seeing your code, it is hard to say what the problem is. It could be any number of things, but look at these:

  1. This is obvious, but your two insert commands are on the same connection (and the connection stays open the whole time) that owns the transaction right?
  2. Are you retrieving your ID related to the constraint after the first insert and writing it back into the data for second insert before executing the command?
  3. The constraint could be set up wrong in the DB.

You definitely do not want to use two transactions.

Jason
  • 1,119
  • 8
  • 9
  • 1. Yes, there is no where for the connection to be closed from inside the transaction. 2. I am setting the ID myself, explicitly before saving the records, and I have checked after the Order is inserted to confirm the ID was not changed by SQL. 3. Not ruling out having done something wrong, but the constraint is nothing more than a FK OrderItem.OrderId to PK Order.OrderId. – jac Nov 03 '09 at 16:41
1

I noticed that you said you were using NetTiers for your code generation.

I've used NetTiers myself and have found that if you delete your foreign key constraint from your table, add it back to the same table and then run the build scripts for NetTiers again after making your changes in the database might help reset the data access layer. I've tried this on occasion with positive results.

Good luck with your issue.

Chris
  • 6,272
  • 9
  • 35
  • 57
  • Deleted the FK, saved the table, added the FK back and regenerated the scripts. Success. I had regenerated a dozen times before this hoping it would fix the problem and nothing, so I don't think it was nettiers, but it's working now so I'm a happy camper. – jac Nov 04 '09 at 15:16
0

Looks like your insert statement for the lineItems is not correctly setting the value for the order .. this should be a result of the Insert order step. Have you looked (and tested) the individual SQL statements?

I do not think your problem has anything to do with transaction control.

Thorsten
  • 12,921
  • 17
  • 60
  • 79
  • I have set the primary key in the order before I Insert it. It is the same value after the insert statement. All the line items have also had the related orderid set before trying to insert them. – jac Nov 03 '09 at 16:00
  • What is the FK constraint checking for? Please add some more information, it may point to another area than the PK of table order ... – Thorsten Nov 03 '09 at 16:17
  • The FK is the OrderItem.OrderId column to the PK Order.OrderId. If I save and commit the Order, then try saving the OrderItems, it works fine. – jac Nov 03 '09 at 16:34
  • Hmmm .. this makes it sound like you are in fact using two different transactions for your inserts. – Thorsten Nov 03 '09 at 18:50
0

I have no experience with this, but it looks like you might have specified a key value that is not available in the parent table. Sorry, but I cannot help you more than this.

Roberto Aloi
  • 30,570
  • 21
  • 75
  • 112
0

The problem is how you handle the error. When an error occurs, a transaction is not automatically rolled back. You can certainly (and probably should) choose to do that, but depending on your app or where you are you may still want to commit it. And in this case, that's exactly what you're doing. You need to wrap some error handling code around there to rollback your code when the error occurs.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • Please understand that I didn't show error handling, rolling back the transaction, etc. For the sake of brevity I tried to show only the summary of the problem without the detail. If it turns out the detail is needed I will post actual code – jac Nov 03 '09 at 16:03
0

The error looks like that the LineItems are not being given the proper FK OrderId that was autogenerated by the the insert of the Order to the Order Table. You say you have checked the Ids, Have you checked the FKs in the order details as well ?

Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
  • Yes. I am using GUIDs for Ids and the primary key and foreign keys are all set before the transaction is opened and all have been checked just before and immediately after the insert statements. – jac Nov 03 '09 at 16:06
  • Then the next thing I'd check is to make sure that the Foreign Key Constraint being referenced in the error message is in fact connecting the correct two tables.. and that it is going in the correct direction. ... and between the right two columns – Charles Bretana Nov 03 '09 at 17:39