Можно сделать следующим образом, на самом верху абстракции сделать слой данных который будет скрывать всю работу с версиями. Таким образом Вы сможете работать с данными использую стандартные операции не заботясь о версиях.
Далее у нас остается только сущность (для простоты пусть будет одна и простая) и она может изменяться. Мы можем выбрать хранить копии или только изменения и при запросы вычислять нужное состояние.
В первом случае нам нужно хранить копии сущностей и вести учет версий, для этого достаточно в самой сущности определить такие данные и помечать последнюю версию, как итоговую.
Во втором случае будет нужен механизм вычисления изменений между версиями и собственно применения их к сущности, при запросе.
Самый простой сценарий. Взять последнюю версию сущности А, изменить и сохранить:
1) обращаемся к слою сервиса (ничего не знает о версиях) с запросом взять сущность А,
2) слой данных запрашивает сущность А и добавляет к запросу пункт о последней версии,
3) получает сущность и отдает сервису, который отдает её нам,
4) изменяем сущность и просим слой сервиса сохранить её,
5) слой данных помечает новую версию как последнюю, а со старой этот статус снимается.
6) сохраняются две сущности, но для нас это будет выглядеть как одна сущность, т.к. мы будем оперировать только одной сущностью.