В TypeORM нет репозиториев

Да, их там действительно нет. Вернее так, там есть что-то с названием «репозиторий», но это не репозиторий. Сейчас объясню почему.

Есть такой паттерн Data Mapper, у которого одного предназначение – гонять данные между доменной моделью и базой, тобишь создавать объекты с данными и сохранять их обратно в бд. Чем, собственно, TypeORM и занимается.

В представлении многих разработчиков это и есть репозиторий. Но у репозитория другая задача – имитировать коллекцию.

Мы же все знаем, что объекты передаются по ссылке. И, следовательно, получив ссылку на объект, можно этот объект мутировать как душе угодно. Но в случае с дата мапером эта идеальная картина мира рушится. Во-первых дата мапер при каждом вызове будет возвращать новый объект, а во-вторых он не будет знать ни о каких манипуляциях с объектом, и по итогу придется вызывать dataMapper.save, чтобы записать состояние объекта в бд.

Кажется сверху дата мапера нужен еще один слой.

Тут в дело вступает репозиторий, который, напомню, имитирует коллекцию объектов. С правильным репозиторием достаточно написать следующий код, чтобы изменить состояние в бд:

Следующее так же будет верно:

Но как изменения попадут в базу? Дата мапер все равно не узнает, что объект мутировал. Кажется все таки нам нужен метод repository.save

Ну нет. У этой проблемы есть решение и имя ему Unit of Work – это еще один патерн, которые реализуется поверх предыдущих двух и следит за границами работы с объектами.

Код с Unit of Work, Repository и Data Mapper выглядел бы так:

По итогу работы этого кода, UoW подсчитал бы все изменения которые произошли в репозиториях и вызвал бы нужные методы у дата маппера, а в базе бы оказалось 2 записи: первая со старым пользователем, у которого обновилось имя, и вторая с новым Гришей.