Consider the following example:
An OData service layer exposes Order and OrderLine resources. A consumer retrieves an Order and its related OrderLines. The consumer edits the Order, edits 1 OrderLine, deletes 1 OrderLine and creates 1 OrderLine. How can the consumer save all of these changes ensuring that the changes are all or nothing?
From what I understand of OData, this will be sent as several service calls:
PUT /api/Order/9999
PUT /api/OrderLine/1001
DELETE /api/OrderLine/1002
POST /api/OrderLine/1002
Each call would be stateless and independent and the server would not be able to determine when to begin and end a transaction.
I've considered various solutions but I'm not sure any of them work:
Solution 1) Have the Order resource contain the OrderLine information. With this solution a single service call would be made with "PUT /api/Order/9999" which would contain all of the OrderLine changes. This strategy seems good because it abstracts the consumer from the transaction details on the server. However, I can't find a way to include the OrderLine collection into the Order entity when PUTting with both Breeze and WCF Data Services Client. Also, I'm not sure how deleting an OrderLine would be communicated in the Order. Is there anything in the OData specification to accomplish this? I found that it's possible to POST related entities in section 10.3.2.2 of the spec. I have not found anything similar for creating/updating/deleting related entities when PUTting an entity.
Solution 2) Using OData's $batch operation would send the 4 service calls as one. I'm not sure if the intention of the $batch feature was for performance or for grouping related service calls into a transaction. Using $batch for transactions, it would be the responsibility of the consumer to determine which service calls to send in the same batch. Is that a proper separation of concerns? On the server side, the batch handler might get complicated. If there was any validation that needed to occur between the Order and OrderLine the batch handler would need to recompose these objects and validate them before attempting the database transactions.
Solution 3) Expose Begin and End transaction service calls. Again, this would be exposing implementation details to the consumer. I think the implications are pretty similar to Solution 2.
The solution must work on .NET 4.0 and the service calls must work from both .NET and javascript clients. Scalability is not a concern. I am using "Web API OData" which will never support the $batch feature in .NET 4.0 but changing over to "WCF Data Services" is a possibility. I chose OData for it's retrieve features but if transactions for CUD operations work better without OData I'm open to suggestions. One possibility is to continue using OData for my application's advanced search screens but to use regular REST services for CUD.
A batch will work for you as the 4 four operations are send together if you are using WCF Data Services. The EF built-in implementation for WCF Data Services will make the changes in the EF operation context together before invoking the SaveChanges, which will be all or nothing if the SaveChanges call fails, emulating the behavior of a transaction.