Обновление сущностей
Entities API позволяет изменять уже существующие сущности через конечную точку /entities/:entityName/:entityId
методом HTTP PUT
.
Обновление сущности
При успешном обновлении сущности возвращается код состояния HTTP 200 - OK
. По умолчанию возвращается представление метаданных сущности в формате JSON, в основном содержащее только атрибут id
для дальнейшего использования.
Пример обновления сущности:
PUT http://localhost:8080/rest
/entities
/sample_Customer
/13f01f59-8e5f-4fd9-802b-66501d49ac99
{
name: "Updated Name"
}
{
"_entityName": "sample_Customer",
"_instanceName": "Updated Name",
"id": "13f01f59-8e5f-4fd9-802b-66501d49ac99"
}
Update Entity API работает аналогично Create Entities API в отношении валидации и ссылок на сущности. Основное различие заключается в том, как обрабатываются ассоциации и композиции 1:N
. Эта операция также позволяет изменять сущности частично, имея в запросе JSON только эти атрибуты.
Атрибуты ассоциации
Если вы хотите обновить атрибут ассоциации 1:1
или N:1
, достаточно отправить новый id ссылаемой сущности. Для ассоциаций 1:N
или M:N
обновленный список ссылок на сущности изменяет то, с чем связана сущность.
Конечная точка Update Entity заменит существующую коллекцию ассоциаций на 1:N или M:N ассоциацию с тем, что является частью запроса. Каждая ссылка на сущность, которая не является частью запроса, будет удалена. Но сущность, на которую была сделана ссылка, не будет удалена из базы данных.
|
В этом примере показано, как обновить ассоциацию M:N
между Product
и ProductTag
. Предполагается, что сохраненный Product до изменения выглядит так:
{
"id": "e1d586b4-aefb-2ee7-3b91-b07357b178ea",
"price": 99.95,
"name": "Outback Power Remote Power System",
"version": 1,
"tags": [
{
"id": "333f3a20-c47b-4bc9-ba34-a72d2d815695",
"name": "shiny"
},
{
"id": "c4c028f0-fec1-7512-83cd-c17537d1f502",
"name": "great"
}
]
}
В этом примере мы хотели бы изменить теги Product следующими способами:
-
great
должен быть удален из тегов. -
amazing
необходимо добавить в теги. -
Тег
shiny
должен быть сохранен.
PUT http://localhost:8080/rest
/entities
/sample_Product
/e1d586b4-aefb-2ee7-3b91-b07357b178ea
?responseFetchPlan=product-with-tags
{
"name": "123",
"price": 99.95,
"tags": [
{
"id": "333f3a20-c47b-4bc9-ba34-a72d2d815695" (1)
},
{
"id": "d6ab132e-a0bd-a624-c6ad-cc544e83c584" (2)
}
]
}
1 | Идентификатор тега продукта shiny является частью запроса на сохранение ассоциации. |
2 | Идентификатор тега продукта amazing вновь добавляется в ассоциацию. |
Поскольку идентификатор тега продукта great (c4c028f0-fec1-7512-83cd-c17537d1f502) больше не является частью запроса, он будет удален из ассоциации.
|
{
"id": "e1d586b4-aefb-2ee7-3b91-b07357b178ea",
"createdBy": "admin",
"price": 99.95,
"name": "Outback Power Remote Power System",
"version": 2,
"tags": [
{
"id": "333f3a20-c47b-4bc9-ba34-a72d2d815695",
"name": "shiny" (1)
},
{
"id": "d6ab132e-a0bd-a624-c6ad-cc544e83c584",
"name": "amazing" (2)
}
]
}
1 | Ссылка shiny все еще присутствует, так как она была частью запроса. |
2 | Ссылка amazing была добавлена, тогда как тег great больше не является частью ассоциации. |
Удалить ссылку на сущность
*:1 Чтобы удалить ссылку ассоциации |
Атрибуты композиции
Если вы хотите обновить атрибут композиции, можно напрямую обновить содержимое дочерней сущности как часть запроса на обновление для родительской сущности. Это возможно как для композиций 1:1
, так и 1:N
.
Операция Update Entity заменит существующую коллекцию элементов композиций тем, что является частью запроса. Вложенные сущности, не являющиеся частью запроса, будут удалены из хранилища данных. Кроме того, убедитесь, что вы передаете одинаковый набор атрибутов для всех элементов композиции. Атрибутам, которые включены в запрос для одной вложенной сущности, но отсутствуют для другой, будет присвоен null в той сущности, для которой их не передали. |
В этом примере показано, как обновить композицию 1:N
между Order
и OrderLine
. Предполагается, что сохраненный Order до изменения выглядит так:
{
"id": "288a5d75-f06f-d150-9b70-efee1272b96c",
"date": "2021-03-01",
"amount": 130.08,
"lines": [
{
"id": "a1cd778b-fe49-4c74-05a0-6fb207dc11bd", (1)
"product": {
"id": "1860904a-5444-9c3e-9dc1-1d7a26d9ac19",
"name": "Solar-One HUP Flooded Battery 48V"
},
"quantity": 2.0,
"version": 1
},
{
"id": "55b925e5-9f3a-a725-9eb3-1240f9c1fe95", (2)
"product": {
"id": "1ed85c7a-89f1-c339-a738-16307ed6003a",
"name": "Cotek Battery Charger"
},
"quantity": 1.0,
"version": 1
}
],
"version": 1,
"customer": {
"id": "f88597ff-009d-1cf2-4a90-a4fb5b08d835",
"name": "Randall Bishop"
}
}
1 | Первая строка заказа ссылается на продукт Solar-One HUP Flooded Battery 48V . |
2 | Вторая строка заказа ссылается на продукт Cotek Battery Charger . |
В этом примере мы хотели бы изменить строки заказа следующим способом:
-
Строка заказа
quantity
с товаромSolar-One HUP Flooded Battery 48V
должна быть изменена на3.0
. -
Строка заказа с товаром
Cotek Battery Charger
должна быть удалена. -
Должна быть добавлена новая строка заказа с продуктом
Outback Power Remote Power System
.
PUT http://localhost:8080/rest
/entities
/sample_Order
/288a5d75-f06f-d150-9b70-efee1272b96c
?responseFetchPlan=product-with-tags
{
"customer": {
"id": "f88597ff-009d-1cf2-4a90-a4fb5b08d835"
},
"date": "2021-03-01",
"amount": 249.99,
"lines": [
{
"id": "a1cd778b-fe49-4c74-05a0-6fb207dc11bd", (1)
"product": {
"id": "1860904a-5444-9c3e-9dc1-1d7a26d9ac19",
"name": "Solar-One HUP Flooded Battery 48V"
},
"quantity": 3.0 (2)
},
{ (3)
"product": {
"id": "f6884077-19c4-546f-33d4-a788399337f7",
"name": "Outback Power Remote Power System"
},
"quantity": 1.0
}
]
}
1 | Идентификатор существующей строки заказа добавляется для ее обновления. |
2 | Значение quantity для продукта 3.0Solar-One HUP Flooded Battery 48V установлено в 3.0 . |
3 | Добавлена новая строка заказа с продуктом Outback Power Remote Power System |
При обновлении дочерней сущности, такой как строка заказа в приведенном выше примере, необходимо добавить идентификатор существующей строки заказа, чтобы Jmix распознал его как обновление. В противном случае он будет рассматривать дочернюю сущность как новую. |
Ответ на этот запрос на обновление содержит желаемые изменения:
{
"id": "288a5d75-f06f-d150-9b70-efee1272b96c",
"date": "2021-03-01",
"amount": 249.99,
"lines": [
{
"id": "d0fdfaa8-7d65-5e25-49c2-d34fc41c0e55",
"product": {
"id": "1860904a-5444-9c3e-9dc1-1d7a26d9ac19",
"name": "Solar-One HUP Flooded Battery 48V"
},
"quantity": 3.0, (1)
"version": 2 (2)
},
{
"id": "96722466-5164-a48c-b7f6-8d4c1bd605dd",
"product": {
"id": "f6884077-19c4-546f-33d4-a788399337f7",
"name": "Outback Power Remote Power System" (3)
},
"quantity": 1.0
}
],
"version": 2,
"customer": {
"id": "f88597ff-009d-1cf2-4a90-a4fb5b08d835",
"name": "Randall Bishop 3"
}
}
1 | Значение quantity для Solar-One HUP Flooded Battery 48V было обновлено. |
2 | Атрибут version был увеличен, чтобы обозначить обновление. |
3 | В заказ добавлена новая строка для Outback Power Remote Power System . |
Строки заказа были успешно обновлены.
Ограничения безопасности для ассоциаций/композиций
Как мы узнали выше, операция Update Entity заменит существующую коллекцию ассоциаций/композиций тем, что является частью запроса. Для каждой ссылки на сущность, которая не является частью запроса, ссылка будет удалена. Кроме того, сущность, на которую ссылались ранее, будет также удалена из приложения.
Имея это в виду, давайте рассмотрим пример сущности с активным ограничением безопасности Jmix на уровне строк:
Предположим, что мы загружаем экземпляр Order
вместе с вложенной коллекцией экземпляров OrderLine
.
Существуют ограничения безопасности, которые отфильтровывают некоторые экземпляры OrderLine
, поэтому мы их не загружаем и не знаем, что они существуют. Например, line5
не загружается клиентом, но существует в базе данных. Если мы обновим Order и удалим line2
из строк заказа, возможны два результата:
-
Если ограничения не изменялись с момента загрузки сущностей, фреймворк восстановит отфильтрованный экземпляр
line5
в коллекции и удалит толькоline2
, что является корректным поведением. -
Если ограничения были изменены таким образом, что теперь
line5
нам доступен, фреймворк не сможет корректно восстановить информацию об отфильтрованных элементах коллекции. В результате иline2
, иline5
будут удалены.
Чтобы исключить возможность потери данных, необходимо отправить специальный системный атрибут в JSON, представляющий наши сущности. Это атрибут __securityToken
, и он включается в результирующий JSON автоматически, если для свойства приложения jmix.core.entitySerializationTokenRequired
задано значение true
.
Как только мы получим этот __securityToken
как часть ответа на загрузку сущности, мы сможем передать значение в запрос обновления сущности. Пример сущности JSON с токеном безопасности:
{
"id": "fa430b56-ceb2-150f-6a85-12c691908bd1",
"lines": [
{
"id": "82e6e6d2-be97-c81c-c58d-5e2760ae095a",
"description": "Item 1"
},
{
"id": "988a8cb5-d61a-e493-c401-f717dd9a2d66",
"description": "Item 2"
}
],
"__securityToken": "0NXc6bQh+vZuXE4Fsk4mJX4QnhS3lOBfxzUniltchpxPfi1rZ5htEmekfV60sbEuWUykbDoY+rCxdhzORaYQNQ==" (1)
}
1 | Токен безопасности — это значение, которое Load Entities API получил ранее. |
Атрибут __securityToken
содержит закодированные идентификаторы отфильтрованных экземпляров, поэтому фреймворк всегда может восстановить необходимую информацию вне зависимости от изменения ограничений.
Частичные обновления
Можно отправлять только те атрибуты, которые должны быть изменены. При этом все остальные атрибуты сущности останутся нетронутыми.
В приведенном ниже примере сущности Order
мы отправим только измененную дату заказа. Хотя сущность Order содержит и другие атрибуты, такие как customer
, amount
, lines
.
PUT http://localhost:8080
/entities
/sample_Order
/5a8adc2f-f4ef-17a9-9f97-1e715b3ade3d
{
"date": "2020-12-06"
}
{
"id": "5a8adc2f-f4ef-17a9-9f97-1e715b3ade3d",
"date": "2020-12-06", (1)
"amount": 130.08, (2)
"version": 2 (3)
}
1 | Атрибут date был изменен с новой датой заказа. |
2 | Остальные атрибуты сущности остаются нетронутыми. |
3 | Атрибут version сущности Order был увеличен, чтобы обозначить обновление. |
Массовое обновление
Update Entity API позволяет обновлять несколько сущностей в одном запросе. Для этого тело запроса JSON должно содержать массив объектов JSON, представляющих каждую сущность.
PUT http://localhost:8080/rest
/entities
/sample_Customer
[
{
"name": "Randall Bishop 2"
},
{
"name": "Sarah Doogle 2"
}
]
[
{
"_entityName": "sample_Customer",
"_instanceName": "Randall Bishop 2",
"id": "833a610b-bc2c-2f44-c67a-2cf8b25f3291"
},
{
"_entityName": "sample_Customer",
"_instanceName": "Sarah Doogle 2",
"id": "c8ab5ae2-7f8f-bc68-fb58-6cfcf7b1d235"
}
]
In case of a violation of an entity validation, the entities will not be created, and a corresponding Error message will be returned. See Entity Validation for further details.