假设您有某种数据结构,该数据结构保留在某种数据库中。为简单起见,我们将此数据结构称为Person
。现在,您要负责设计CRUD API,该API允许其他应用程序创建,读取,更新和删除Person
。为简单起见,让我们假定通过某种Web服务访问此API。
对于CRUD的C,R和D部分,设计很简单。我将使用类似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
和有意将其更改为null之间做出区别?将签名更改为
void UpdatePerson(Identifier, Person, ListOfFieldNamesToUpdate)
。将签名更改为
void UpdatePerson(Identifier, ListOfFieldValuePairs)
。使用传输协议的某些功能:例如,您可以忽略Person的JSON表示中未包含的所有字段。但是,这通常需要您自己解析JSON,并且无法使用库的内置功能(例如WCF)。
在我看来,所有解决方案都不是很优雅。当然,这是一个普遍的问题,那么每个人使用的最佳实践解决方案是什么?
Person
仍未持久的新创建实例,并且在将标识符确定为持久性机制的一部分的情况下,只需将其保留为null。至于答案,JPA使用版本号。如果阅读版本23,则更新项目(如果DB中的版本为24)将导致写入失败。