Допустим, у вас есть какая-то структура данных, которая сохраняется в какой-то базе данных. Для простоты назовем эту структуру данных Person
. Теперь перед вами стоит задача разработать CRUD API, который позволяет другим приложениям создавать, читать, обновлять и удалять Person
файлы. Для простоты предположим, что этот API доступен через какой-то веб-сервис.
Для C, R и D частей CRUD дизайн прост. Я буду использовать C # -подобную функциональную нотацию - реализация может быть SOAP, REST / JSON или чем-то еще:
class Person {
string Name;
DateTime? DateOfBirth;
...
}
Identifier CreatePerson(Person);
Person GetPerson(Identifier);
void DeletePerson(Identifier);
Как насчет обновления? Естественная вещь будет
void UpdatePerson(Identifier, Person);
но как бы вы указали, какие поля Person
для обновления?
Решения, которые я мог бы придумать:
Вы всегда можете потребовать передачи полного лица, то есть клиент будет делать что-то вроде этого, чтобы обновить дату рождения:
p = GetPerson(id); p.DateOfBirth = ...; UpdatePerson(id, p);
Однако это потребует некоторой согласованности транзакций или блокировки между Get и Update; в противном случае вы можете перезаписать некоторые другие изменения, сделанные параллельно другим клиентом. Это сделало бы API намного сложнее. Кроме того, он подвержен ошибкам, поскольку следующий псевдокод (при условии, что клиентский язык поддерживает JSON)
UpdatePerson(id, { "DateOfBirth": "2015-01-01" });
- что выглядит правильно - не только изменит DateOfBirth, но и сбросит все остальные поля в null.
Вы можете игнорировать все поля, которые есть
null
. Однако, как бы вы тогда делали разницу между не изменениемDateOfBirth
и намеренным изменением его на ноль ?Измените подпись на
void UpdatePerson(Identifier, Person, ListOfFieldNamesToUpdate)
.Измените подпись на
void UpdatePerson(Identifier, ListOfFieldValuePairs)
.Используйте некоторые возможности протокола передачи: например, вы можете игнорировать все поля, не содержащиеся в JSON-представлении Person. Однако для этого обычно требуется анализировать JSON самостоятельно и не иметь возможности использовать встроенные функции вашей библиотеки (например, WCF).
Ни одно из решений не кажется мне действительно элегантным. Конечно, это обычная проблема, так что же такое решение для всех?
источник
Person
экземпляров, которые все еще не сохранены, и в случае, если идентификатор определен как часть механизма сохранения, просто оставьте его равным нулю. Что касается ответа, JPA использует номер версии; если вы читаете версию 23, при обновлении элемента, если версия в БД - 24, запись завершается неудачно.PUT
иPATCH
методы. При использованииPATCH
следует заменять только ключи отправки, приPUT
этом весь объект заменяется.Ответы:
Если у вас нет отслеживания изменений в качестве требования к этому объекту (например, «Пользователь Джон изменил имя и дату рождения»), проще всего было бы переопределить весь объект в БД тем, который вы получили от потребителя. Этот подход будет включать немного больше данных, передаваемых по проводам, но вы избегаете чтения перед обновлением.
Если у вас есть требование отслеживания активности. Ваш мир намного сложнее, и вам нужно будет спроектировать, как хранить информацию о действиях CRUD и как их перехватывать. Это мир, в который вы не хотите погружаться, если у вас нет таких требований.
Что касается переопределения значений отдельными транзакциями, я бы предложил провести исследование вокруг оптимистической и пессимистической блокировки . Они смягчают этот общий сценарий:
У каждого пользователя разные транзакции, поэтому стандартный SQL с этим. Наиболее распространенной является оптимистическая блокировка (также упоминается @ SJuan76 в комментарии о версиях). Ваша версия, ваша запись в БД и во время записи вы сначала заглядываете в БД, если версии совпадают. Если версии не совпадают, вы знаете, что кто-то обновил объект тем временем, и вам нужно ответить об этом потребителю сообщением об ошибке. Да, вы должны показать эту ситуацию пользователю.
Обратите внимание, что перед записью необходимо прочитать фактическую запись из БД (для сравнения версий с оптимистической блокировкой), поэтому реализация дельта-логики (запись только измененных значений) может не потребовать дополнительного запроса на чтение перед записью.
Использование дельта-логики сильно зависит от контракта с потребителем, но обратите внимание, что для потребителя проще всего построить полную полезную нагрузку вместо дельты.
источник
У нас есть PHP API на работе. Для обновлений, если поле не отправлено в объекте JSON, ему присваивается значение NULL. Затем он передает все хранимой процедуре. Хранимая процедура пытается обновить каждое поле с помощью field = IFNULL (input, field). Поэтому, если в объекте JSON находится только 1 поле, обновляется только это поле. Чтобы явно очистить поле набора, мы должны иметь поле = '', затем БД обновит поле либо пустой строкой, либо значением этого столбца по умолчанию.
источник
Укажите обновленный список полей в строке запроса.
PUT /resource/:id?fields=name,address,dob Body { //resource body }
Реализация слияния хранимых данных с моделью из тела запроса:
источник