How Do SQL Transactions Work?

1.5k views Asked by At

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?

6

There are 6 answers

1
Chris On BEST ANSWER

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.

4
Thorsten On

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.

0
Roberto Aloi On

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.

1
Joel Coehoorn On

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.

2
Charles Bretana On

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 ?

1
Jason On

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.