В смысле Эрика Эвана, управляемого доменом (http://domaindrivendesign.org/index.htm), вы должны сначала подумать о своих агрегатах. Затем вы создаете свои репозитории вокруг них.
Существует множество методов обработки агрегатов, которые связаны друг с другом. Чаще всего я использую, чтобы агрегаты могли связываться друг с другом только через интерфейс только для чтения. Одна из ключевых идей Aggregates заключается в том, что вы не можете изменить состояние базовых объектов, не пройдя корень. Поэтому, если Продукт и Пользователь являются корневыми агрегатами в вашей модели, я не смогу обновить Продукт, если попал в него через Пользователь-> Заказ-> Продукт. Я должен получить продукт из репозитория продукта, чтобы отредактировать его. (С точки зрения пользовательского интерфейса вы можете сделать так, чтобы пользователь выглядел как Пользователь-> Заказ-> Продукт, но когда вы попадаете на экран редактирования Продукта, вы получаете объект из Репозитория продуктов).
Когда вы смотрите на Продукт (в коде), перейдя из Пользователь-> Заказ-> Продукт, вы должны смотреть на Интерфейс Продукта, который не имеет никакого способа изменить основное состояние Продукта (только не получает комплекты и т. д.)
Организуйте свои Агрегаты и их хранилища по способу их использования. Я вижу, что User и Prodcut являются их собственными агрегатами и имеют свои собственные репозитории. Из вашего описания я не уверен, должен ли Заказ принадлежать Пользователю или также быть отдельным.
В любом случае используйте интерфейс только для чтения, когда агрегаты связаны. Когда вам нужно перейти с одного агрегата на другой, идите за ним из собственного репозитория.
Если ваши репозитории кэшируются, то при загрузке заказа (через пользователя) загружаются только идентификаторы продуктов из базы данных. Затем загрузите данные из хранилища продуктов, используя идентификатор продукта. Вы можете немного оптимизировать, загружая любые другие инварианты в Продукт по мере загрузки Заказа.