Модель домена-репозитории-связь между подсистемами
В настоящее время я разрабатываю систему, которая будет использовать несколько источников данных для получения требуемых данных. Я пытаюсь смоделировать концепции, показанные ниже (разместил бы изображение, но не хватает точек!) где клиент может иметь связь с рядом продуктов. Клиент будет храниться в "подсистеме клиента", а продукт и CustomerProduct будут храниться в"подсистеме продукта"
public class Customer
{
public string FirstName { get; set; }
public Guid ID { get; set; }
}
public class CustomerProduct
{
public Guid ID { get; set; }
public Customer Customer { get; set; }
public Product Product { get; set; }
}
public class Product
{
public string Name { get; set; }
public double Price { get; set; }
public Guid ID { get; set; }
}
Сущность "клиент" будет физически сохраняется в системе, доступ к которой должен осуществляться через веб-сервис. Сущности" ConsumerProduct "и" Product " будут сохранены в базе данных SQL, используя NHibernate в качестве ORM.
В рамках проекта я планировал использовать репозитории для абстрагирования технологий сохранения данных от модели предметной области. Поэтому у меня было бы 3 интерфейса репозитория, ICustomerRepository, ICustomerProductRepository и IProductRepository. Затем я бы создал конкретную реализацию NHibernate для в CustomerProduct и хранилища продукта и конкретного веб-сервиса доступ к реализации репозитория клиента.
Я борюсь с тем, как будут взаимодействовать сущности, которые сохраняются в различных подсистемах. В идеале я хотел бы иметь богатую модель домена, где сущность CustomerProduct будет иметь физическое свойство "Customer", которое возвращает объект Customer. Однако я понятия не имею, как это будет работать, поскольку сущность клиента должна быть доступна из другое хранилище данных.Единственный способ, который я вижу, чтобы решить эту проблему, - это не поддерживать полную ссылку на клиента в сущности CustomerProduct, а вместо этого просто держать ссылку, а затем каждый раз, когда мне нужно получить ссылку на клиента, я бы просто пошел через репозиторий клиентов.
Я был бы признателен за любые предложения, которые кто-либо мог бы выдвинуть о том, как решить эту проблему.1 ответ:
Привет, я не был в вашей ситуации раньше, но у меня есть домены проектирования, которые взаимодействуют с другими подсистемами. У меня нет полной картины, но кажется, что сущность клиента более изолирована от других, CustomerProduct и Product. Так правильно ли я предполагаю, что вы представите модель в общем графическом интерфейсе, но его только источник данных, которые разделены?
Во-первых, вы можете решить эту проблему различными способами, и вы также должны спросить себя о нефункциональных требованиях такие как техническое обслуживание, время безотказной работы и поддержка. Будут ли обе системы всегда работать одновременно или случится так, что вы возьмете на себя систему вниз. Подсказка, которую я ищу, заключается в том, должны ли вы передавать синхронизацию или асинхронность (очередь сообщений?) с подсистемами. Это может быть достигнуто с помощью NServiceBus.
Но чтобы сосредоточиться на вашем домене, вы должны сделать так, чтобы домен выглядел так, как будто у него есть только одна модель. Это может быть достигнуто различными способами:1) имейте свой ICustomerRepository (an интерфейсный контракт, который действует как работает против коллекции объектов) будет реализован связанным с инфраструктурой репозиторием, который использует ваш веб-сервис в вашей подсистеме. Намек, что вы должны использовать GUID в качестве ключей так keyconfilcts произойти. Этот подход не позволит вам иметь какие-либо отношения/ассоциации с клиентом из других ваших сущностей. Они будут, но только через хранилище (это решение, которое Джимми Нильссон использует в своей книге (http://jimmynilsson.com/blog/), чтобы не затяните модель со многими двунаправленными отношениями).
2) зависит от того, как ваши варианты использования будут нацелены / использовать модель, но вы можете создать широкий уровень обслуживания приложений, который находится в одном физическом месте, но использует CustomerService и CustomerProcuctService и ProductService. Чтобы предотвратить утечку логики домена на уровень приложения, некоторая координация между этими сущностями может быть инкапсулирована в обработчиках событий домена, которые координируют некоторые события между различными объектами. сервисы.
3) вы также можете создать класс CustomerAdapter, который имеет другие подсистемы CustomerGUID в качестве ключа (он не может генерировать ключи, так как веб-служба клиента имеет контроль над этим). Но вы можете сопоставить его в Nhibernate и иметь отношения между CustomerProduct и CustomerAdapter. Но когда вы сопоставляете CustomerAdapter, вы загружаете только GUID. Затем убедитесь, что у вас будет ICustomerAdapterService, введенный в свойство с помощью Spring.Net Виндзор или какой-нибудь другой Ди-инструмент. Тогда ты к не сопоставлять свойства (например, customername, adress и т. д.) Для customerAdapter в Nhibernate. Но когда вы получаете/читаете адрес от CustomerAdapter, он получит его от ICustomerAdapterService и установит все другие значения. Это не рекомендуется, так как это нарушит некоторые правила DDD, например, отсутствие служб в модели домена. Но если вы смотрите на это с этой точки зрения: это действительно можно считать доменной службой, так как она решает проблему в вашем распределенном домене. Однако он включает в себя связанные с инфраструктурой вещи, такие как реализация службы WCF, и поэтому реализация службы должна быть в другом инфраструктурном слое / сборке
Наиболее простым является решение 2, Если вы можете справиться с тем фактом, что сущность Customer будет доступна только службе в прикладном уровне. Однако это приложение serviclayer может быть хорошим антикоррупционным слоем между двумя подсистемами. Вероятно, есть причина, по которой у вас сегодня две подсистемы. Но вот пример взаимодействия потоков (без подробного представления о том, как устроен ваш домен):
- GUI вызывает службу приложений CustomerProductService метод BuyNewProduct (CustomerDTO customer, ProductDTO newProduct)
- CustomerProductService имеют ICustomerProductRepository и IProductRepository, введенных в конструктор. Он также будет иметь службу инфраструктуры ICustomerFacadeService (изменить имя теперь : -)), которая вводится в свойство CustomerFacadeService. Создание этой услуги осуществляется с помощью фабрика, которая имеет два метода создания, Create () и CreateExtendendedWithCustomerService (). Более поздний также введет CustomerServiceFacade
- метод BuyNewProduct(...) теперь соберет CustomerDTO и использует CustomerGUID для загрузки клиента из CustomerFacadeService, который вызовет веб-службу в другой подсистеме.
- загруженный клиент будет гарантировать, что он действительно существует, но теперь мы загружаем продукт с IProductRepository
- с обоими CustomerGUID value and Product Entity мы создаем новую сущность CustomerProduct (которая на самом деле является просто классом сопоставления между продуктами и GUID клиента) и сохраняем ее через ICustomerProductRepository
- Теперь вы можете позвонить в другую службу инфраструктуры, чтобы отправить клиенту электронное письмо с уведомлением о том, что у него есть доступ к новому продукту. Или вы можете создать доменные события в сущности CustomerProduct, которая делегирует это уведомление en eventhandler (на уровне службы приложений) это ввело IEmailService в ctor. Затем вы инкапсулировали знание домена для отправки уведомлений при подключении нового клиента к продукту.
Надеюсь, это поможет вам в моделировании вашего домена с меньшей болью. Потому что это больно делать DDD. Требует много дискуссий с коллегами, экспертами предметной области и самим собой перед зеркалом :) это правильный путь? Посмотри на это. DDDsample.net для доменных событий или поиска Udi Dahan и домена события.
Я пишу ответ здесь, больше места:
Относительно CustomerAdadpter также упоминается как CustomerFacadeService в Примере потока взаимодействия вот мое мнение: как реализовать зависит от вашего приложения. Большинство пользователей будут вызывать mainsystem, вызывая вашу "облачную подсистему", которая будет иметь хорошее время безотказной работы: - тогда вам, возможно, не нужна очередь, и у вас будет служба WCF в облаке. Ваш CustomerFacadeService будет оболочкой службы, которая просто предоставляет метод ваш прикладной уровень нуждается, а также собрать все необходимые объекты DTO. Если ваша облачная система также обратится к вашей основной системе, то вам нужно предоставить некоторые из ваших методов в качестве сервиса. Затем у вас есть возможность предоставить конечную точку NServiceBus в качестве службы WCF. Это дает вам возможность снять главную систему без потери информации. Но всегда есть много "но"... Вам, конечно, нужно иметь службу WCF на другой машине, если ваши инфра-технические ребята хотят установить исправления / перезагрузка веб-сервера основной системы. Если у вас есть клиент ждет ответа, пока основная система не работает, как долго они будут ждать? Думаю, не слишком долго. Таким образом, один из сценариев, в котором я вижу преимущества этого, заключается в том, что у вас есть пакеты/отчеты, которые необходимо выполнить, и если одна часть системы не работает, отчетность будет продолжаться, как только она снова поднимется.
Вот некоторый пример NServiceBus, представленного как служба WCF. Но у меня нет опыта в том, чтобы делать именно это, просто знание "это можно сделать". http://docs.particular.net/nservicebus/architecture/nservicebus-and-wcf