ProductRepository должен быть внедрен в ProductService и выполнять все действия с этим агрегатом с конкретными возвращаемыми данными для моего уровня представления.
Это не строгое правило. Сервисы могут нуждаться в дополнительных репозиториях, а могут и не нуждаться в них. Они организуют косвенность между границами. Если границы разные агрегаты, то хорошо, но это может быть и между агрегатами и удаленными сервисами/репозиториями. Возможностей много. У некоторых сервисов даже нет репозитория. Но самое главное, что не ко всем репозиториям нужно обращаться через сервис. Основная причина существования сервисов — это не репозиторий, который можно спрятать. Это оркестровка. Чтобы упростить доступ к очень специализированным заданиям, которые не полностью связаны с доменом.
Не лучше ли использовать CQRS для разделения моего запроса и команд? ... ProductService должен быть разделен на ProductReadService, который создает необработанный SQL, и ProductWriteService, которые используют мой репозиторий, или даже разделить мой репозиторий для записи и чтения?
Нет по умолчанию. Я имею в виду, что CQRS — отличная стратегия, но она может привести к ненужной сложности. Размер дизайна должен соответствовать задаче, которую он решает. Если решение сложнее, чем проблема, которую оно решает, вам будет сложно продать реализацию.
Это говорит о том, что если вы обнаружите, что ваши потребности как в запросах, так и в командах развиваются с разной скоростью, а изменения вызываются разными силами (требованиями), так что вам трудно скрыть и то, и другое, тогда сегрегация может быть решением. Не потому, что один читает, а другой только пишет, а потому, что разные сервисы и репозитории могут работать с разными моделями. В этом суть CQRS. Он не разделяет только чтение и письмо. Так же и с моделями. Даже с базами данных в некоторых случаях.
Так что начните с малого. Будь проще. Делайте его более изощренным по мере появления потребностей.
Рекомендую посмотреть эти видео для лучшего погружения в вопрос: