Supponiamo che tu abbia un qualche tipo di struttura di dati, che è persistente in un qualche tipo di database. Per semplicità, chiamiamo questa struttura di dati Person
. Ora ti viene assegnato il compito di progettare un'API CRUD, che consente ad altre applicazioni di creare, leggere, aggiornare ed eliminare messaggi Person
. Per semplicità, supponiamo che questa API sia accessibile tramite un qualche tipo di servizio web.
Per le parti C, R e D di CRUD, il design è semplice. Userò la notazione funzionale simile a C # - l'implementazione potrebbe essere SOAP, REST / JSON o qualcos'altro:
class Person {
string Name;
DateTime? DateOfBirth;
...
}
Identifier CreatePerson(Person);
Person GetPerson(Identifier);
void DeletePerson(Identifier);
Che dire dell'aggiornamento? La cosa naturale da fare sarebbe
void UpdatePerson(Identifier, Person);
ma come specificare quali campi Person
aggiornare?
Soluzioni che ho potuto escogitare:
Potresti sempre richiedere il passaggio di una Persona completa , ovvero il cliente farebbe qualcosa del genere per aggiornare la data di nascita:
p = GetPerson(id); p.DateOfBirth = ...; UpdatePerson(id, p);
Tuttavia, ciò richiederebbe una sorta di coerenza transazionale o blocco tra Get e Update; in caso contrario, è possibile sovrascrivere alcune altre modifiche apportate in parallelo da un altro client. Ciò renderebbe l'API molto più complicata. Inoltre, è soggetto a errori, poiché il seguente pseudo-codice (presupponendo una lingua client con supporto JSON)
UpdatePerson(id, { "DateOfBirth": "2015-01-01" });
- che sembra corretto - non cambierebbe solo DateOfBirth ma ripristinerebbe anche tutti gli altri campi su null.
Potresti ignorare tutti i campi che lo sono
null
. Tuttavia, come faresti a fare la differenza tra non cambiarlaDateOfBirth
e cambiarla deliberatamente in null ?Cambia la firma in
void UpdatePerson(Identifier, Person, ListOfFieldNamesToUpdate)
.Cambia la firma in
void UpdatePerson(Identifier, ListOfFieldValuePairs)
.Utilizzare alcune funzionalità del protocollo di trasmissione: ad esempio, è possibile ignorare tutti i campi non contenuti nella rappresentazione JSON della persona. Tuttavia, ciò di solito richiede di analizzare JSON da soli e di non essere in grado di utilizzare le funzionalità integrate della libreria (ad esempio WCF).
Nessuna delle soluzioni mi sembra davvero elegante. Sicuramente, questo è un problema comune, quindi qual è la soluzione delle migliori pratiche utilizzata da tutti?
Person
istanze di nuova creazione che non sono ancora persistenti e nel caso in cui l'identificatore venga deciso come parte del meccanismo di persistenza, lasciarlo a null. Per quanto riguarda la risposta, JPA utilizza un numero di versione; se leggi la versione 23, quando aggiorni l'articolo se la versione nel DB è 24 la scrittura fallisce.