Допустим, у вас есть какая-то структура данных, которая сохраняется в какой-то базе данных. Для простоты назовем эту структуру данных 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, запись завершается неудачно.