Załóżmy, że masz jakąś strukturę danych, która jest utrwalona w jakiejś bazie danych. Dla uproszczenia nazwijmy tę strukturę danych Person
. Masz teraz zadanie zaprojektowania interfejsu CRUD API, który pozwala innym aplikacjom tworzyć, czytać, aktualizować i usuwać Person
s. Dla uproszczenia załóżmy, że dostęp do tego interfejsu API można uzyskać za pośrednictwem usługi internetowej.
W przypadku części CRUD C, R i D konstrukcja jest prosta. Użyję notacji funkcjonalnej podobnej do C # - implementacją może być SOAP, REST / JSON lub coś innego:
class Person {
string Name;
DateTime? DateOfBirth;
...
}
Identifier CreatePerson(Person);
Person GetPerson(Identifier);
void DeletePerson(Identifier);
Co z aktualizacją? Naturalną rzeczą do zrobienia byłoby
void UpdatePerson(Identifier, Person);
ale jak określisz, które pola Person
chcesz zaktualizować?
Rozwiązania, które mógłbym wymyślić:
Zawsze możesz wymagać przekazania pełnej Osoby, tzn. Klient zrobiłby coś takiego, aby zaktualizować datę urodzenia:
p = GetPerson(id); p.DateOfBirth = ...; UpdatePerson(id, p);
Wymagałoby to jednak pewnego rodzaju spójności transakcyjnej lub blokowania między Get a Update; w przeciwnym razie możesz zastąpić inną zmianę wykonaną równolegle przez innego klienta. Sprawiłoby to, że interfejs API byłby znacznie bardziej skomplikowany. Ponadto jest podatny na błędy, ponieważ następujący pseudo-kod (zakładając język klienta z obsługą JSON)
UpdatePerson(id, { "DateOfBirth": "2015-01-01" });
- który wygląda poprawnie - nie tylko zmieni DateOfBirth, ale także zresetuje wszystkie inne pola do null.
Możesz zignorować wszystkie pola, które są
null
. Jak jednak zrobiłbyś różnicę między niezmienianiemDateOfBirth
a celowym zmienianiem go na zero ?Zmień podpis na
void UpdatePerson(Identifier, Person, ListOfFieldNamesToUpdate)
.Zmień podpis na
void UpdatePerson(Identifier, ListOfFieldValuePairs)
.Użyj pewnej funkcji protokołu transmisji: na przykład możesz zignorować wszystkie pola nie zawarte w reprezentacji JSON osoby. Zwykle wymaga to jednak samodzielnego przeanalizowania JSON i niemożności korzystania z wbudowanych funkcji biblioteki (np. WCF).
Żadne z rozwiązań nie wydaje mi się naprawdę eleganckie. Z pewnością jest to powszechny problem, więc jakie jest najlepsze rozwiązanie stosowane przez wszystkich?
Person
instancji, które nadal nie są utrwalane, a jeśli identyfikator jest ustalany jako część mechanizmu trwałości, pozostaw go zerowy. Jeśli chodzi o odpowiedź, JPA używa numeru wersji; jeśli czytasz wersję 23, po zaktualizowaniu elementu, jeśli wersja w DB to 24, zapis nie powiedzie się.