diff --git a/examples/Common.CorrespondingContentIDs-sample.json b/examples/Common.CorrespondingContentIDs-sample.json
new file mode 100644
index 000000000..82188075b
--- /dev/null
+++ b/examples/Common.CorrespondingContentIDs-sample.json
@@ -0,0 +1,42 @@
+{
+ "$Version": "4.0",
+ "$Reference": {
+ "https://sap.github.io/odata-vocabularies/vocabularies/Common.json": {
+ "$Include": [{ "$Namespace": "com.sap.vocabularies.Common.v1", "$Alias": "Common" }]
+ }
+ },
+ "corresponding.sample": {
+ "$Alias": "self",
+ "SalesQuotation": { "$Kind": "EntityType", "id": { "$Nullable": true } },
+ "SalesQuotationItemToBeCopied": { "$Kind": "ComplexType", "product": { "$Nullable": true } },
+ "SalesOrder": {
+ "$Kind": "EntityType",
+ "Items": { "$Kind": "NavigationProperty", "$Collection": true, "$Type": "self.SalesOrderItem" }
+ },
+ "SalesOrderItem": {
+ "$Kind": "EntityType",
+ "Discounts": { "$Kind": "NavigationProperty", "$Collection": true, "$Type": "self.SalesOrderItemDiscount" }
+ },
+ "SalesOrderItemDiscount": {
+ "$Kind": "EntityType",
+ "percent": { "$Type": "Edm.Decimal", "$Nullable": true, "$Scale": 0 }
+ },
+ "CreateSalesOrder": [
+ {
+ "$Kind": "Action",
+ "$IsBound": true,
+ "$Parameter": [
+ { "$Name": "_it", "$Type": "self.SalesQuotation" },
+ { "$Name": "items", "$Collection": true, "$Type": "self.SalesQuotationItemToBeCopied" }
+ ],
+ "$ReturnType": { "$Type": "self.SalesOrder" },
+ "@Common.CorrespondingContentIDs": [{ "ParameterValue": "items", "ReturnedEntity": "$ReturnType/Items" }]
+ }
+ ],
+ "default": {
+ "$Kind": "EntityContainer",
+ "SalesQuotations": { "$Collection": true, "$Type": "self.SalesQuotation" }
+ }
+ },
+ "$EntityContainer": "corresponding.sample.default"
+}
diff --git a/examples/Common.CorrespondingContentIDs-sample.xml b/examples/Common.CorrespondingContentIDs-sample.xml
new file mode 100644
index 000000000..7ab191f57
--- /dev/null
+++ b/examples/Common.CorrespondingContentIDs-sample.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vocabularies/Common.json b/vocabularies/Common.json
index 548852c06..4523fdff1 100644
--- a/vocabularies/Common.json
+++ b/vocabularies/Common.json
@@ -1316,6 +1316,41 @@
"@Common.Experimental": true,
"@Core.IsURL": true,
"@Core.Description": "Base URL for WebSocket connections"
+ },
+ "CorrespondingContentIDs": {
+ "$Kind": "Term",
+ "$Collection": true,
+ "$Type": "Common.CorrespondingContentID",
+ "$AppliesTo": ["Action"],
+ "@Common.Experimental": true,
+ "@Core.Description": "Correspondence between `Core.ContentID` in a parameter and in the return type of an action",
+ "@Core.LongDescription": "If values in the action invocation are annotated with `Core.ContentID`,\n the corresponding entities returned by the action are annotated with the same `Core.ContentID`\n and can thus be referenced in subsequent requests within the same batch request."
+ },
+ "CorrespondingContentID": {
+ "$Kind": "ComplexType",
+ "@Common.Experimental": true,
+ "@Core.Description": "Establishes a correspondence between a value or entity in a parameter and in the return type",
+ "@Core.LongDescription": "Given a sales quotation with items for coffee, sugar and paper,\nthe following $batch request to [this service](../examples/Common.CorrespondingContentIDs-sample.xml)\ninvokes an action to create a sales order for sugar and paper\nand adds a 10% discount for the sugar.\n```json\n{\n \"requests\": [\n {\n \"id\": \"1\",\n \"method\": \"post\",\n \"url\": \"/service/SalesQuotation(68)/self.CreateSalesOrder\",\n \"body\": {\n \"items\": [\n {\"product\": \"Sugar\", \"@Core.ContentID\": \"I1\"},\n {\"product\": \"Paper\"}\n ]\n }\n },\n {\n \"id\": \"2\",\n \"dependsOn\": [ \"1\" ],\n \"method\": \"post\",\n \"url\": \"$I1/Discounts\",\n \"body\": {\n \"percent\": 10\n }\n }\n ]\n}\n```\nIn the response to the action invocation the sales order item for the sugar is annotated\nwith `\"@Core.ContentID\": \"I1\"`. The subsequent POST request can reference this item without knowing its key.\n\nExactly one of `ParameterValue` and `ParameterEntity` and\nexactly one of `ReturnedValue` and `ReturnedEntity` and must be given.",
+ "ParameterValue": {
+ "$Type": "Edm.PropertyPath",
+ "$Nullable": true,
+ "@Core.Description": "Path to a value in a parameter that may be annotated with `Core.ContentID`"
+ },
+ "ParameterEntity": {
+ "$Type": "Edm.NavigationPropertyPath",
+ "$Nullable": true,
+ "@Core.Description": "Path to an entity in a parameter that may be annotated with `Core.ContentID`"
+ },
+ "ReturnedValue": {
+ "$Type": "Edm.PropertyPath",
+ "$Nullable": true,
+ "@Core.Description": "Path to a value in the return type that will be annotated with the same `Core.ContentID`"
+ },
+ "ReturnedEntity": {
+ "$Type": "Edm.NavigationPropertyPath",
+ "$Nullable": true,
+ "@Core.Description": "Path to an entity in the return type that will be annotated with the same `Core.ContentID`"
+ }
}
}
}
diff --git a/vocabularies/Common.md b/vocabularies/Common.md
index c2469172c..1d225eab3 100644
--- a/vocabularies/Common.md
+++ b/vocabularies/Common.md
@@ -111,6 +111,7 @@ Term|Type|Description
[mediaUploadLink](Common.xml#L1457) *([Experimental](Common.md#Experimental))*|URL|URL for uploading new media content to a Document Management Service
In contrast to the `@odata.mediaEditLink` this URL allows to upload new media content without directly changing a stream property or media resource. The upload request typically uses HTTP POST with `Content-Type: multipart/form-data` following RFC 7578. The upload request must contain one multipart representing the content of the file. The `name` parameter in the `Content-Disposition` header (as described in RFC 7578) is irrelevant, but the `filename` parameter is expected. If the request succeeds the response will contain a JSON body of `Content-Type: application/json` with a JSON property `readLink`. The newly uploaded media resource can be linked to the stream property by changing the `@odata.mediaReadLink` to the value of this `readLink` in a subsequent PATCH request to the OData entity.
[PrimitivePropertyPath](Common.xml#L1472) *([Experimental](Common.md#Experimental))*|[Tag](https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Core.V1.md#Tag)|A term or term property with this tag whose type is (a collection of) `Edm.PropertyPath` MUST resolve to a primitive structural property
[WebSocketBaseURL](Common.xml#L1477) *([Experimental](Common.md#Experimental))*|URL|Base URL for WebSocket connections
+[CorrespondingContentIDs](Common.xml#L1483) *([Experimental](Common.md#Experimental))*|\[[CorrespondingContentID](#CorrespondingContentID)\]|Correspondence between `Core.ContentID` in a parameter and in the return type of an action
If values in the action invocation are annotated with `Core.ContentID`, the corresponding entities returned by the action are annotated with the same `Core.ContentID` and can thus be referenced in subsequent requests within the same batch request.
## [TextFormatType](Common.xml#L120)
@@ -441,3 +442,50 @@ Use terms [Aggregation.RecursiveHierarchy](https://github.com/oasis-tcs/odata-vo
**Type:** String
User ID
+
+
+## [CorrespondingContentID](Common.xml#L1492) *([Experimental](Common.md#Experimental))*
+Establishes a correspondence between a value or entity in a parameter and in the return type
+
+Given a sales quotation with items for coffee, sugar and paper,
+the following $batch request to [this service](../examples/Common.CorrespondingContentIDs-sample.xml)
+invokes an action to create a sales order for sugar and paper
+and adds a 10% discount for the sugar.
+```json
+{
+ "requests": [
+ {
+ "id": "1",
+ "method": "post",
+ "url": "/service/SalesQuotation(68)/self.CreateSalesOrder",
+ "body": {
+ "items": [
+ {"product": "Sugar", "@Core.ContentID": "I1"},
+ {"product": "Paper"}
+ ]
+ }
+ },
+ {
+ "id": "2",
+ "dependsOn": [ "1" ],
+ "method": "post",
+ "url": "$I1/Discounts",
+ "body": {
+ "percent": 10
+ }
+ }
+ ]
+}
+```
+In the response to the action invocation the sales order item for the sugar is annotated
+with `"@Core.ContentID": "I1"`. The subsequent POST request can reference this item without knowing its key.
+
+Exactly one of `ParameterValue` and `ParameterEntity` and
+exactly one of `ReturnedValue` and `ReturnedEntity` and must be given.
+
+Property|Type|Description
+:-------|:---|:----------
+[ParameterValue](Common.xml#L1532)|PropertyPath?|Path to a value in a parameter that may be annotated with `Core.ContentID`
+[ParameterEntity](Common.xml#L1535)|NavigationPropertyPath?|Path to an entity in a parameter that may be annotated with `Core.ContentID`
+[ReturnedValue](Common.xml#L1538)|PropertyPath?|Path to a value in the return type that will be annotated with the same `Core.ContentID`
+[ReturnedEntity](Common.xml#L1541)|NavigationPropertyPath?|Path to an entity in the return type that will be annotated with the same `Core.ContentID`
diff --git a/vocabularies/Common.xml b/vocabularies/Common.xml
index e52534711..c85d2aebf 100644
--- a/vocabularies/Common.xml
+++ b/vocabularies/Common.xml
@@ -1480,6 +1480,68 @@ If the request succeeds the response will contain a JSON body of `Content-Type:
+
+
+
+
+ If values in the action invocation are annotated with `Core.ContentID`,
+ the corresponding values returned by the action are annotated with the same `Core.ContentID`
+ and can thus be referenced in subsequent requests within the same batch request.
+
+
+
+
+
+
+ Given a sales quotation with items for coffee, sugar and paper,
+the following $batch request to [this service](../examples/Common.CorrespondingContentIDs-sample.xml)
+invokes an action to create a sales order for sugar and paper
+and adds a 10% discount for the sugar.
+```json
+{
+ "requests": [
+ {
+ "id": "1",
+ "method": "post",
+ "url": "/service/SalesQuotation(68)/self.CreateSalesOrder",
+ "body": {
+ "items": [
+ {"product": "Sugar", "@Core.ContentID": "I1"},
+ {"product": "Paper"}
+ ]
+ }
+ },
+ {
+ "id": "2",
+ "dependsOn": [ "1" ],
+ "method": "post",
+ "url": "$I1/Discounts",
+ "body": {
+ "percent": 10
+ }
+ }
+ ]
+}
+```
+In the response to the action invocation the sales order item for the sugar is annotated
+with `"@Core.ContentID": "I1"`. The subsequent POST request can reference this item without knowing its key.
+
+Exactly one of `ParameterValue` and `ParameterEntity` and
+exactly one of `ReturnedValue` and `ReturnedEntity` and must be given.
+
+
+
+
+
+
+
+
+
+
+
+
+
+