-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PATCH Member of a Collection Sends all Fields Instead of Changed Fields #883
Comments
Hi @SpaceCondor, thanks for reaching our to us. I will reach out to our PO (@newtork) to discuss whether we can find time to implement this feature. Thanks and best regards, |
If needed I can construct the request directly as opposed to utilizing the cloud SDK so it is more of an inconvenience. Within SAP B1, the Service Layer will often produce errors when doing PATCH requests and sending entire objects. |
Hi @SpaceCondor, Currently we are in preparation for the upcoming next major release. This will likely keep us busy within the next weeks. Please let me know in case this request is much more urgent and requires higher priority. The following request could be used as workaround while leveraging our Generic OData Client: final String jsonPayload = "{"
+ " \"OrderLines\": ["
+ " {"
+ " \"LineNum\": 2,"
+ " \"Price\": 100"
+ " }"
+ " ]"
+ "}";
final ODataEntityKey entityKey = ODataEntityKey.of(Collections.singletonMap("OrderId", 12345), ODataProtocol.V2);
final ODataRequestUpdate request = new ODataRequestUpdate(
"/service/path/", // service path
"Orders", // entity set name
entityKey,
jsonPayload,
UpdateStrategy.MODIFY_WITH_PATCH,
null, // no version identifier
ODataProtocol.V2);
final HttpDestination httpDestination = DestinationAccessor.getDestination("MyDestination").asHttp();
final HttpClient httpClient = HttpClientAccessor.getHttpClient(httpDestination);
request.execute(httpClient); Best regards |
@newtork Thank you for the feedback and I completely understand regarding the launch of version 4 of the SDK being a priority. I will use the provided workaround for now and if it becomes more urgent I will let you know. Thanks again! |
Hey @newtork I just wanted to know if this has been resolved? |
Hey, unfortunately we didn't get around to implementing this, and we currently don't have it planned. But as you might have seen, we moved the SDK to open source in the meanwhile. So if you want you could even give this a shot yourself and contribute 😄 However, looking at this again I'm not sure if the exact above example is allowed by OData V4. Because the specification states:
To me this reads like the full list content is required. Furthermore, using PATCH on a collection property directly is explicitly not allowed. Am I missing something in the spec? Also, I assume the service you are working with does allow this behavior in practice? If the collection is a navigation property, there is the option to update related entities when patching. By default, here also the full list has to be given. But one can also provide a delta like so:
But this feature is only supported with OData 4.01, not 4.0. And I think this only applies to navigation properties, not collections of complex types. Thus adding this into the SDK would require some form of feature toggle. |
@MatKuhr You are correct that this technically does not abide by the specification, however this is behavior implemented by the SAP Business One Service Layer. There is a blog post from SAP here about it: https://community.sap.com/t5/enterprise-resource-planning-blogs-by-sap/sap-business-one-service-layer-entity-crud-update/ba-p/13171993 The important bit is the following:
|
Interesting, okay. In that case we anyway should be careful with implementing anything in the SDK, as we aim to only offer OOTB functionality for things that are conforming to the spec. Maybe an easier workaround is also to just do something like: Function<List<LinteItem>, List<LinteItem>> update; // some update logic
var updatedList = update.apply(order.getOrderLines());
var updatesOnlyList = updatedList.stream().filter(it -> !it.getChangedFields().isEmpty()).toList();
order.setOrderLines(updatesOnlyList);
order = orderService.updateOrder(order); With the last line assuming the service responds with the entity and the full list. If not, one could manually reset the object to contain the full list. Didn't try it, but the |
@MatKuhr Unfortunately that will not work, that would send only lines with changed fields, but for those lines it would send all fields. I was thinking about adding an override here: From: if( input instanceof VdmComplex ) {
changedFields = ((VdmObject<?>) input).toMapOfFields();
changedFields.putAll(((VdmObject<?>) input).getCustomFields());
} else {
changedFields = ((VdmObject<?>) input).getChangedFields();
} To: if( input instanceof VdmComplex && !sendOnlyChangedVdmComplexFields /* <-----Override flag */) {
changedFields = ((VdmObject<?>) input).toMapOfFields();
changedFields.putAll(((VdmObject<?>) input).getCustomFields());
} else {
changedFields = ((VdmObject<?>) input).getChangedFields();
} Not sure if this is something that would be considered, but it is needed for my use case. |
and that is not supported by the B1 service? Naively, I'd think updating all properties is just a special case of updating some properties 😄 Anyhow, what might actually be an alternative solution is to create a small custom implementation of the |
Unfortunately no, the presence of certain fields in And that is a great idea for overriding the |
@Nonnull
@Override
public class DocumentLinePatch extends DocumentLine {
@Nonnull
@Override
protected Map<String, Object> toMapOfFields() {
Map<String, Object> mapOfFields = super.toMapOfFields();
mapOfFields.keySet().retainAll(this.changedOriginalFields.keySet());
return mapOfFields;
}
} Did the trick! Not sure why I didn't think of that. I'll close this issue now. Thanks so much for the help. 👍 |
Happy that it worked 🥳 Also, I didn't know about the |
Issue Description
When modifying a member of a collection property of an object and then issuing a PATCH request, the entire collection and all properties are sent as opposed to just the member and properties that have been updated.
A real world scenario would be updating the sales price of the second line of an order.
Example Code:
In the above scenario I'd expect to see a request like:
But instead I am getting all order lines and all fields of all order lines.
I understand that I can exclude particular fields from updates and also force include fields, but I don't think I can specify the above behavior?
The text was updated successfully, but these errors were encountered: