Hello, gentlemen.
After some digging into the source code I found that it seems to be impossible to pass batch changes AND execute an Action in the same HTTP REQUEST.
It is very frustrating, it was the very first scenario I started with when making feasibility study on WCF DS. Did no one asked you for such a feature?
The scenario:
In business domain, there is OrderHead aggregating OrderLines. In a WPF form user edits Order Head details AND make any changes to Order Lines (in editable grid, including add/delete lines). After that, user clicks button "Confirm Order", server runs huge amount of logic over the CHANGED order+lines data.
For that scenario, on server I would expect to create an Action "Confirm" with the OrderHead as first parameter. And there, I would expect that all the user changes in the OrderHead AND in all its Lines are already in EF ObjectContext, and I would prefer
doing all this work in single transaction, single unit of work.
Question: What did you guys think about how such a scenario should be realized.
Another question: Can anyone tell me why in the code below (BatchSaveResult.GenerateBatchRequest()) there a switch: either Queries or ChangedEntries, but NOT BOTH? What is the logic behind?
private ODataRequestMessageWrapper GenerateBatchRequest() { if (this.ChangedEntries.Count == 0 && this.Queries == null) { this.SetCompleted(); return (ODataRequestMessageWrapper) null; } else { ODataRequestMessageWrapper batchRequest = this.CreateBatchRequest(); using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(batchRequest, this.RequestInfo)) { ODataUtils.SetHeadersForPayload(messageWriter, ODataPayloadKind.Batch); batchRequest.FireSendingRequest2((Descriptor) null); this.batchWriter = messageWriter.CreateODataBatchWriter(); this.batchWriter.WriteStartBatch(); if (this.Queries != null) { for (int index = 0; index < this.Queries.Length; ++index) { ODataRequestMessageWrapper requestMessage = this.CreateRequestMessage(this.RequestInfo.BaseUriResolver.CreateAbsoluteUriIfNeeded(this.Queries[index].QueryComponents(this.RequestInfo.MaxProtocolVersion).Uri), "GET"); Version version = this.Queries[index].QueryComponents(this.RequestInfo.MaxProtocolVersion).Version; WebUtil.SetOperationVersionHeaders(requestMessage, version, this.RequestInfo.MaxProtocolVersionAsVersion); requestMessage.FireSendingRequest2((Descriptor) null); } } else if (0 < this.ChangedEntries.Count) { this.batchWriter.WriteStartChangeset(); ClientEdmModel model = ClientEdmModel.GetModel(this.RequestInfo.MaxProtocolVersion); for (int index = 0; index < this.ChangedEntries.Count; ++index) { Descriptor descriptor = this.ChangedEntries[index]; if (!descriptor.ContentGeneratedForSave) { EntityDescriptor entityDescriptor = descriptor as EntityDescriptor; if (descriptor.DescriptorKind == DescriptorKind.Entity) { if (entityDescriptor.State == EntityStates.Added) { if (ClientTypeUtil.GetClientTypeAnnotation((IEdmModel) model, model.GetOrCreateEdmType(entityDescriptor.Entity.GetType())).IsMediaLinkEntry || entityDescriptor.IsMediaLinkEntry) throw System.Data.Services.Client.Error.NotSupported(System.Data.Services.Client.Strings.Context_BatchNotSupportedForMediaLink); } else if ((entityDescriptor.State == EntityStates.Unchanged || entityDescriptor.State == EntityStates.Modified) && entityDescriptor.SaveStream != null) throw System.Data.Services.Client.Error.NotSupported(System.Data.Services.Client.Strings.Context_BatchNotSupportedForMediaLink); } else if (descriptor.DescriptorKind == DescriptorKind.NamedStream) throw System.Data.Services.Client.Error.NotSupported(System.Data.Services.Client.Strings.Context_BatchNotSupportedForNamedStreams); ODataRequestMessageWrapper requestMessage = descriptor.DescriptorKind != DescriptorKind.Entity ? this.CreateRequest((LinkDescriptor) descriptor) : this.CreateRequest(entityDescriptor); requestMessage.FireSendingRequest2(descriptor); this.CreateChangeData(index, requestMessage); } } this.batchWriter.WriteEndChangeset(); } this.batchWriter.WriteEndBatch(); this.batchWriter.Flush(); } return batchRequest; } }
Roman Koreshkov, systems architect