如何在不更新或创建根节点的情况下通过 oData 创建新的子节点实体
How to create a new Child node entity via oData without updating or creating the root node
我在 S/4HANA 云中创建了一个自定义业务对象,它包括一个父节点和一个子节点,还为 S/4HANA 自定义 OData 服务生成了 Java VDM。我将它与 SAP Cloud Platform SDK 结合起来进行服务开发(我再也找不到它的 SAP 帮助页面了)。
场景是能够只向现有的根节点添加一个新的子节点。
当我尝试使用其他字段值对 ParentEntitySet()/childNavigation 执行 POST 操作时,我收到一条错误消息“无效的方法调用:'CREATE' 方法在非根实体上被调用'YY1_CHILD_ENTITY'.
我该怎么做才能解决这个错误?
更新:
旧代码导致了我所描述的错误
@Create(serviceName = "CrudService", entity = "ChildEntitySet", sourceEntity = "ParentEntitySet")
public CreateResponse createABC(CreateRequest createRequest) {
EntityData entity = createRequest.getData();
LeaveRequest response;
try {
response = new CreateChildCommand(new ErpConfigContext(), new DefaultService(), entity)
.execute();
} catch (HystrixBadRequestException e) {
return CreateResponse.setError(new ErrorResponseImpl(400, null, e.getMessage(), e.getCause(), null));
}
CreateResponse readResponse = CreateResponse.setSuccess().setData(response).response();
return readResponse;
}
新代码:错误消失了,但当我尝试 post 带有导航的子实体时出现新错误。
Inavalid Entity name: No entity with name ParentClass(guid'<parentKey>')/to_ChildEntity in the OData service
但是当我使用上面相同的导航进行查询时 url,它工作得很好。只有带导航的创建才有这个问题
@Create(serviceName = "CrudService", entity = "ChildEntitySet", sourceEntity = "ParentEntitySet")
public CreateResponse createChild(CreateRequest createRequest) {
EntityData entity = createRequest.getData();
String parentKey = (String) createRequest.getSourceKeys().get(<parentKey>);
ChildClass response = new ChildClass();
Map<String, Object> childEntity = new HashMap<>();
try {
childEntity = entity.asMap();
response.setParentKey((String) entity.asMap().get(<parentKey>));
response.setText((String) entity.asMap().get("Text"));
response.setCreatedBy((String) entity.asMap().get("CreatedBy"));
response.setCreatedOn((Calendar) entity.asMap().get("CreatedOn"));
ParentClass parent = new ParentReadByKeyCommand(new ErpConfigContext(), parentKey)
.execute();
parent.createChildEntity(childEntity);
return CreateResponse.setSuccess().setData(response).response();
} catch (Exception e) {
// Return an instance of QueryResponse containing the error in case of failure
ErrorResponse errorResponse = ErrorResponse.getBuilder().setMessage(e.getMessage())
.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR).setCause(e).response();
return CreateResponse.setError(errorResponse);
}
}
下面的方法属于ParentClass
public ChildClass createChildEntity(Map<String, Object> childEntity) throws ODataException {
if (erpConfigContext == null) {
throw new ODataException(ODataExceptionType.OTHER, "Failed to fetch related objects of type ChildClass.",
new IllegalStateException(
"Unable to execute OData query. The entity was created locally without an assigned ERP configuration context. This method is applicable only on entities which were retrieved or created using the OData VDM."));
}
final StringBuilder odataResourceUrl = new StringBuilder(getEntityCollection());
odataResourceUrl.append("(");
odataResourceUrl.append(ODataTypeValueSerializer.of(EdmSimpleTypeKind.Guid).toUri(<parentKey>));
odataResourceUrl.append(")/");
odataResourceUrl.append("to_ChildEntity");
final ODataCreateRequestBuilder builder = ODataCreateRequestBuilder
.withEntity(getEndpointUrl(), odataResourceUrl.toString()).withBodyAsMap(childEntity);
final ODataCreateRequest query = builder.build();
final ODataCreateResult result = query.execute(erpConfigContext);
final ChildClass entity = result.as(ChildClass.class);
entity.setErpConfigContext(erpConfigContext);
return entity;
}
我正在使用
<parent>
<groupId>com.sap.cloud.servicesdk.prov</groupId>
<artifactId>projects-parent</artifactId>
<version>1.19.0</version>
</parent>
<dependencies>
<dependency>
<groupId>com.sap.cloud.s4hana</groupId>
<artifactId>sdk-parent</artifactId>
<version>1.11.1</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.sap.cloud.s4hana</groupId>
<artifactId>s4hana-all</artifactId>
<!-- <version>1.11.1</version> -->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
一些 OData API 只允许通过根实体创建子实体。
不过,目前 S/4HANA Cloud SDK 的 VDM 不支持此功能。
如果有更新,我会更新这个答案。
更新:
使用 2.4.1 版 S/4 HANA Cloud SDK 现在可以将实体创建为另一个实体的子实体。
代码可能如下所示:
new YourCustomService()
.createChildEntity(childEntity)
.asChildOf(parentEntity, ParentEntity.TO_CHILD_ENTITY)
.execute();
或者更实际的使用SDK提供的BusinessPartner的例子:
new DefaultBusinessPartnerService().createBusinessPartnerAddress(someAddress)
.asChildOf(
someBusinessPartner,
BusinessPartner.TO_BUSINESS_PARTNER_ADDRESS
)
.execute();
我在 S/4HANA 云中创建了一个自定义业务对象,它包括一个父节点和一个子节点,还为 S/4HANA 自定义 OData 服务生成了 Java VDM。我将它与 SAP Cloud Platform SDK 结合起来进行服务开发(我再也找不到它的 SAP 帮助页面了)。
场景是能够只向现有的根节点添加一个新的子节点。
当我尝试使用其他字段值对 ParentEntitySet()/childNavigation 执行 POST 操作时,我收到一条错误消息“无效的方法调用:'CREATE' 方法在非根实体上被调用'YY1_CHILD_ENTITY'.
我该怎么做才能解决这个错误?
更新:
旧代码导致了我所描述的错误
@Create(serviceName = "CrudService", entity = "ChildEntitySet", sourceEntity = "ParentEntitySet")
public CreateResponse createABC(CreateRequest createRequest) {
EntityData entity = createRequest.getData();
LeaveRequest response;
try {
response = new CreateChildCommand(new ErpConfigContext(), new DefaultService(), entity)
.execute();
} catch (HystrixBadRequestException e) {
return CreateResponse.setError(new ErrorResponseImpl(400, null, e.getMessage(), e.getCause(), null));
}
CreateResponse readResponse = CreateResponse.setSuccess().setData(response).response();
return readResponse;
}
新代码:错误消失了,但当我尝试 post 带有导航的子实体时出现新错误。
Inavalid Entity name: No entity with name ParentClass(guid'<parentKey>')/to_ChildEntity in the OData service
但是当我使用上面相同的导航进行查询时 url,它工作得很好。只有带导航的创建才有这个问题
@Create(serviceName = "CrudService", entity = "ChildEntitySet", sourceEntity = "ParentEntitySet")
public CreateResponse createChild(CreateRequest createRequest) {
EntityData entity = createRequest.getData();
String parentKey = (String) createRequest.getSourceKeys().get(<parentKey>);
ChildClass response = new ChildClass();
Map<String, Object> childEntity = new HashMap<>();
try {
childEntity = entity.asMap();
response.setParentKey((String) entity.asMap().get(<parentKey>));
response.setText((String) entity.asMap().get("Text"));
response.setCreatedBy((String) entity.asMap().get("CreatedBy"));
response.setCreatedOn((Calendar) entity.asMap().get("CreatedOn"));
ParentClass parent = new ParentReadByKeyCommand(new ErpConfigContext(), parentKey)
.execute();
parent.createChildEntity(childEntity);
return CreateResponse.setSuccess().setData(response).response();
} catch (Exception e) {
// Return an instance of QueryResponse containing the error in case of failure
ErrorResponse errorResponse = ErrorResponse.getBuilder().setMessage(e.getMessage())
.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR).setCause(e).response();
return CreateResponse.setError(errorResponse);
}
}
下面的方法属于ParentClass
public ChildClass createChildEntity(Map<String, Object> childEntity) throws ODataException {
if (erpConfigContext == null) {
throw new ODataException(ODataExceptionType.OTHER, "Failed to fetch related objects of type ChildClass.",
new IllegalStateException(
"Unable to execute OData query. The entity was created locally without an assigned ERP configuration context. This method is applicable only on entities which were retrieved or created using the OData VDM."));
}
final StringBuilder odataResourceUrl = new StringBuilder(getEntityCollection());
odataResourceUrl.append("(");
odataResourceUrl.append(ODataTypeValueSerializer.of(EdmSimpleTypeKind.Guid).toUri(<parentKey>));
odataResourceUrl.append(")/");
odataResourceUrl.append("to_ChildEntity");
final ODataCreateRequestBuilder builder = ODataCreateRequestBuilder
.withEntity(getEndpointUrl(), odataResourceUrl.toString()).withBodyAsMap(childEntity);
final ODataCreateRequest query = builder.build();
final ODataCreateResult result = query.execute(erpConfigContext);
final ChildClass entity = result.as(ChildClass.class);
entity.setErpConfigContext(erpConfigContext);
return entity;
}
我正在使用
<parent>
<groupId>com.sap.cloud.servicesdk.prov</groupId>
<artifactId>projects-parent</artifactId>
<version>1.19.0</version>
</parent>
<dependencies>
<dependency>
<groupId>com.sap.cloud.s4hana</groupId>
<artifactId>sdk-parent</artifactId>
<version>1.11.1</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.sap.cloud.s4hana</groupId>
<artifactId>s4hana-all</artifactId>
<!-- <version>1.11.1</version> -->
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
一些 OData API 只允许通过根实体创建子实体。
不过,目前 S/4HANA Cloud SDK 的 VDM 不支持此功能。
如果有更新,我会更新这个答案。
更新: 使用 2.4.1 版 S/4 HANA Cloud SDK 现在可以将实体创建为另一个实体的子实体。
代码可能如下所示:
new YourCustomService()
.createChildEntity(childEntity)
.asChildOf(parentEntity, ParentEntity.TO_CHILD_ENTITY)
.execute();
或者更实际的使用SDK提供的BusinessPartner的例子:
new DefaultBusinessPartnerService().createBusinessPartnerAddress(someAddress)
.asChildOf(
someBusinessPartner,
BusinessPartner.TO_BUSINESS_PARTNER_ADDRESS
)
.execute();