Я согласен, что вариант 1 неразумный. Модель домена (модель обновления в CQRS, а не модель чтения) должна иметь только указатели первичных ключей на другие домены, не поддерживающие данные из этих доменов.
Вариант 2 лучше, но все еще не совсем там. Я не являюсь поклонником API-вызовов между доменами при использовании Event Sourcing, потому что это может привести к сбою одного домена или его медленной работе из-за трудностей во втором. В вашем примере наличие домена Invoice вызывает API в домене User для получения имени пользователя для перестройки модели чтения. Это означает, что, если домен User не работает, домен Invoice не может завершить его перестроение - домен Invoice завершается сбоем по собственной вине.
Рассмотрим вариант 3 кэширования информации о пользователе в домене Invoice. Создайте прослушиватели для соответствующих пользовательских событий в домене Invoice и кешируйте необходимые пользовательские данные там - в этом случае только первичный ключ и имя пользователя, но вы можете добавить дополнительные поля позже, если это необходимо. Ваша модель чтения счета-фактуры затем перестраивается с использованием этого кэша, поэтому нет зависимости от домена пользователя.
Просто пояснительная записка, чтобы убедиться, что мы все на одной странице, и для тех читателей, которые новички вCQRS. Модель чтения счета должна содержать ID пользователя и имя пользователя, но модель домена должна иметь только ID пользователя. Чтение моделей повсюду дублирует информацию и не предназначено для третьей нормальной формы;они должны быть очень быстрыми и содержать всю информацию, которая будет отображаться на экране.