Прогресс REST PUT на классическом сервере возвращает ошибку

У меня есть тестовая таблица под названием 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.

Процедура компилируется хорошо, аннотации добавляются Define Service Interface функциональностью в OpenEdge. В узле Defined Services я создал сопоставления для параметров (я пропущу readCities, потому что он работает хорошо) для putCities и глагола PUT:

  1. Ресурсы: /PutCities
  2. Глагольная ассоциация: Verb='PUT' -> test..putCities
  3. Mapping Definitions for Input: параметр ttCities подключен к разделу запроса HTTP Message -> Body напрямую (не к параметру body)
  4. Определения сопоставления для вывода: ответ ttCities подключен к Interface Parameters -> ttCities

Мой клиентский код очень прост - взят из какой-то статьи Progress KB, а в проекте есть OpenEdge.Net.pl библиотек, включенных в PROPATH:

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?

Любая помощь будет оценена.


person Maciej S.    schedule 01.02.2019    source источник
comment
Я думаю, что сообщение означает то, что оно говорит. Вы пытаетесь создать город, который уже существует. Вы показываете определение таблицы, а затем говорите, что вы вручную добавили город 1, Бостон, и что FOR EACH показывает, что он существует в базе данных. Вы не упомянули, что удалили его — так что же произойдет, если вы измените ttCities.ID на 2, а ttCities.City на Нью-Йорк?   -  person Tom Bascom    schedule 01.02.2019
comment
Уважаемый г-н Bascom, как я уже сказал, когда ID = 2, новая запись создается правильно. И Вы правы - я не удалил запись с ID = 1. Но в целом я думаю, что я делаю некоторые ошибки, вызванные .NET ORM... Я думаю о PUT иначе, чем я должен... ORM позаботятся об операции PUT сами по себе, поэтому мне не нужно думать о какой-либо пользовательской логике в методах. Это мое плохое конечно.   -  person Maciej S.    schedule 01.02.2019
comment
Моя вина. Я как-то не увидел ту часть, где вы уже пробовали id=2.   -  person Tom Bascom    schedule 02.02.2019


Ответы (1)


Думаю дело в следующем:

Вы создаете свою временную таблицу «как» таблица вашей базы данных, поэтому она наследует уникальный индекс, а также понятное имя таблицы «Города». Ваш ReadCities создает запись временной таблицы для каждой записи базы данных, поэтому у нас есть одна с идентификатором 1.

Однако ваш клиентский код создает запись временной таблицы с идентификатором 1, но затем переходит к коду ReadCities и получает все записи базы данных, и в этот момент вы получаете сообщение об ошибке, поскольку там уже есть запись временной таблицы с идентификатором идентификатор 1.

Вероятно, вы можете доказать это, поместив сообщения в свой код, чтобы определить, в какой момент получена ошибка. Я предполагаю, что если вы поместите сообщение перед «lReturnValue = oJson: Read (hCities)». и еще одно после него, что вы получите первое сообщение перед ошибкой.

person jdpjamesp    schedule 04.02.2019
comment
Я мог бы получить такое сообщение из моей временной таблицы - это правда, но я получил его из БД (посмотрите на имя таблицы в моем описании - это Cities, а не ttCities). Но Вы направили меня к правильному решению - создание временной таблицы с предложением LIKE в этом случае является проблемой, потому что временная таблица, созданная таким образом, связана с целевой таблицей. Я могу сделать это на стороне клиента, и код работает нормально, но на стороне сервера это должно быть определено вручную в коде. Спасибо. - person Maciej S.; 05.02.2019