【问题标题】:Progress REST PUT in classic server returns error经典服务器中的进度 REST PUT 返回错误
【发布时间】:2019-06-26 02:20:21
【问题描述】:

我有一个名为Cities 的测试表。创建脚本如下:

ADD TABLE "Cities"
  AREA "Schema Area"
  LABEL "Cities"
  DUMP-NAME "Cities"

ADD FIELD "ID" OF "Cities" AS integer
  DESCRIPTION "ID"
  INITIAL 0
  LABEL "ID"
  COLUMN-LABEL "ID"
  ORDER 10

ADD FIELD "City" OF "Cities" AS character
  DESCRIPTION "City name"
  FORMAT "x(30)"
  INITIAL ""
  LABEL "Cities"
  MAX-WIDTH 30
  COLUMN-LABEL "Cities"
  ORDER 20

ADD INDEX "IxID" ON "Cities" 
  AREA "Schema Area"
  UNIQUE
  PRIMARY
  INDEX-FIELD "ID" ASCENDING 
.
PSC
cpstream=1250
.
0002253205

我已在此表中添加了一条记录:

create Cities.
assign
    Cities.ID = 1
    Cities.City = "Boston".

FOR EACH 例程通过一条记录显示正确的结果。

我创建了一些带有经典服务器设置的 REST 项目,用于学习和测试目的。所有服务器和配置都是标准的,因为安装者配置了它们。 我在 AppServer 文件夹(文件:test.p)中添加了一些程序并在其中创建了临时表。完整程序代码:

BLOCK-LEVEL ON ERROR UNDO, THROW.

DEFINE TEMP-TABLE ttCities LIKE Cities.

@openapi.openedge.export(type="REST", useReturnValue="false", writeDataSetBeforeImage="false").
PROCEDURE readCities:

    DEFINE OUTPUT PARAMETER TABLE FOR ttCities.

    FOR EACH Cities NO-LOCK:
        CREATE ttCities.
        BUFFER-COPY Cities TO ttCities.
    END.

END PROCEDURE.

@openapi.openedge.export(type="REST", useReturnValue="false", writeDataSetBeforeImage="false").
PROCEDURE putCities:

    DEFINE INPUT-OUTPUT PARAMETER TABLE FOR ttCities.

END PROCEDURE.

过程编译良好,注释由 OpenEdge 中的Define Service Interface 功能添加。 在Defined Services 节点中,我为putCities 和PUT 动词创建了参数映射(我将省略readCities,因为它运行良好):

  1. 资源:/PutCities
  2. 动词关联:Verb='PUT' -> test..putCities
  3. 输入的映射定义:参数 ttCities 直接连接到请求 HTTP Message -> Body 部分(而不是正文参数)
  4. 输出的映射定义:响应 ttCities 连接到 Interface Parameters -> ttCities

我的客户端代码非常基本 - 取自一些 Progress KB 文章,项目在 PROPATH 中包含 OpenEdge.Net.pl 库:

BLOCK-LEVEL ON ERROR UNDO, THROW.

USING Progress.Json.ObjectModel.JsonObject.
USING Progress.Json.ObjectModel.*.
USING Progress.Json.ObjectModel.ObjectModelParser.
USING Progress.Lang.Object.
USING OpenEdge.Core.WidgetHandle.
USING OpenEdge.Core.String.
USING OpenEdge.Net.HTTP.IHttpRequest.
USING OpenEdge.Net.HTTP.IHttpResponse.
USING OpenEdge.Net.HTTP.ClientBuilder.
USING OpenEdge.Net.HTTP.RequestBuilder.
DEFINE VARIABLE oRequest  AS IHttpRequest  NO-UNDO.
DEFINE VARIABLE oResponse AS IHttpResponse NO-UNDO.
DEFINE VARIABLE oEntity   AS Object        NO-UNDO.
DEFINE VARIABLE lcHTML    AS LONGCHAR      NO-UNDO.
DEFINE VARIABLE hXmlDoc   AS HANDLE        NO-UNDO.
DEFINE VARIABLE hCities AS HANDLE NO-UNDO.
DEFINE VARIABLE oJson AS JsonObject NO-UNDO.
DEFINE VARIABLE lReturnValue AS LOGICAL NO-UNDO.

DEFINE TEMP-TABLE ttCities LIKE Cities.

hCities = TEMP-TABLE ttCities:HANDLE.

create ttCities.
assign
    ttCities.ID = 1
    ttCities.City = "Boston".

oJson = NEW JsonObject().
lReturnValue = oJson:Read(hCities).

oRequest = RequestBuilder:Put('http://127.0.0.1:8980/REST6/rest/REST6/PutCities', oJson):Request.
oResponse = ClientBuilder:Build():Client:Execute(oRequest).

MESSAGE oResponse:StatusCode oResponse:StatusReason VIEW-AS ALERT-BOX.

/* some other code to parse response */

这段代码编译得很好,但是调用它会给出这个错误: Cities already exists with ID 1.

我想在服务器上调用了该过程,但由于此错误而无法更新数据库记录。据我所知,调用 PUT 方法应该在记录中执行更新 - 而不是创建新的。此外,将 ttCities.ID 更改为值 2 还会创建新记录。

所以我的问题很简单:如何处理这个问题?我应该在putCities 过程中编写自己的自定义逻辑吗?

任何帮助将不胜感激。

【问题讨论】:

  • 我认为消息的意思是它所说的。您正在尝试创建一个已经存在的城市。您显示表的定义,然后说您手动添加了城市 1,波士顿,并且 FOR EACH 显示它存在于数据库中。您没有提到您已将其删除 - 那么如果您将 ttCities.ID 更改为 2 并将 ttCities.City 更改为“New York”会发生什么?
  • 尊敬的 Bascom 先生,正如我所说,当 ID = 2 新记录正确创建时。你是对的 - 我没有删除 ID = 1 的记录。但总的来说,我认为我犯了一些由 .NET ORM 引起的错误......我以不同的方式思考 PUT,我应该...... ORM 小心关于 PUT 操作本身,所以我不必考虑方法中的任何自定义逻辑。那当然是我的错。
  • 过失。我不知何故没有看到你已经尝试过 id = 2 的部分。

标签: rest web-services put openedge progress-4gl


【解决方案1】:

我认为问题如下:

您创建“类似”数据库表的临时表,以便它继承唯一索引以及“Cities”的表友好名称。 您的 ReadCities 为每个数据库记录创建一个临时表记录,因此我们有一个 ID 为 1 的记录。

您的客户端代码虽然创建了一个 ID 为 1 的临时表记录,但随后转到 ReadCities 代码并获取所有数据库记录,此时您会收到错误,因为已经有一个临时表记录那里的 ID 为 1。

您可以通过在代码中添加消息来确定在什么时候收到错误来证明这一点。我想如果您在“lReturnValue = oJson:Read(hCities)”之前添加一条消息。然后是另一个,您将收到错误之前的第一条消息。

【讨论】:

  • 我可以从我的临时表中得到这种消息——这是真的,但我是从数据库中得到的(查看我描述中的表名——它是Cities 而不是ttCities)。但是您指导我找到正确的解决方案 - 在这种情况下,使用 LIKE 子句创建临时表是一个问题,因为以这种方式创建的临时表与目标表链接。我可以在客户端做到这一点并且代码工作正常,但在服务器端它应该在代码中手动定义。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 2019-06-05
  • 2013-09-15
  • 2018-09-30
相关资源
最近更新 更多