领域模型ߝ存储库 –跨子系统的通信

发布于 2024-10-31 00:53:03 字数 1169 浏览 1 评论 0原文

我目前正在设计一个系统,该系统将使用多个数据源来消费所需的数据。我正在尝试对下面所示的概念进行建模(将发布图像,但没有足够的点!),其中客户可以与多种产品建立关联。客户将存储在“客户子系统”中,产品和客户产品将存储在“产品子系统”中。

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; }
}

“客户”实体将物理地持久存储在必须通过 Web 服务访问的系统中。 “ConsumerProduct”和“Product”实体将使用 NHibernate 作为 ORM 持久保存在 SQL 数据库中。

作为设计的一部分,我计划使用存储库将数据持久性技术从域模型中抽象出来。因此,我将有 3 个存储库接口:ICustomerRepository、ICustomerProductRepository 和 IProductRepository。然后,我将为 CustomerProduct 和 Product 存储库创建一个具体的 NHibernate 实现,并为 Customer 存储库创建一个具体的 Web 服务访问实现。

我正在努力解决的是保留在不同子系统中的实体如何交互。理想情况下,我想要一个丰富的域模型,其中 CustomerProduct 实体将具有一个物理“Customer”属性,该属性返回一个 Customer 对象。但是我不知道这将如何工作,因为需要从不同的数据存储访问客户实体。

我认为解决此问题的唯一方法是不在 CustomerProduct 实体中维护对 Customer 的完整引用,而是仅保留一个引用,然后每次我需要获取对 Customer 的引用时,我都会通过 Customer存储库。

对于任何人就如何解决此问题提出的任何建议,我将不胜感激。

I am currently in the process of designing a system which will use multiple data sources to consume the required data. I am attempting to model the concepts shown below (would post an image but don't have enough points!) where a customer can have an association with a number of products. The Customer would be stored in the "Customer subsystem" and the Product and CustomerProduct would be stored in thee "Product subsystem"

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; }
}

The “Customer” entity will be physically persisted in a system which must be accessed via a web-service. The “ConsumerProduct” and “Product” entities will be persisted in a SQL database, using NHibernate as the ORM.

As part of the design I was planning to use Repositories to abstract the data persistence technologies away from the domain model. Therefore I would have 3 repository interfaces, ICustomerRepository, ICustomerProductRepository and IProductRepository. I would then create a concrete NHibernate implementation for the CustomerProduct and Product repositories and a concrete web service access implementation for the Customer repository.

What I am struggling with is how the entities, which are persisted in different sub-systems will interact. Ideally I would like a rich domain model, where the CustomerProduct entity would have a physical “Customer” property which returns a Customer object. However I have no idea how this would work as the Customer entity would need to be accessed from a different data store.

The only way I can see to solve this issue is to not maintain a full reference to Customer in the CustomerProduct entity and instead just hold a reference, and then every time I need to get a reference to the Customer I would just go via the Customer Repository.

I would be grateful for any suggestions anyone could put forward on how to solve this issue.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

十年不长 2024-11-07 00:53:03

您好,我以前没有遇到过您的情况,但我设计了与其他子系统通信的域。
我没有全面的了解,但客户实体似乎与其他实体(客户产品和产品)更加隔离。那么我的猜测是否正确,您将在通用 GUI 中呈现模型,但它只是分离的数据源?

首先,您可以通过不同的方式解决这个问题,您还应该询问自己非功能性需求,例如维护、正常运行时间和支持。两个系统是否始终同时启动并运行,或者您是否会关闭系统?我正在寻找的线索是您应该与子系统进行同步还是异步(消息队列?)通信。这可以通过使用 NServiceBus 来实现。

但为了专注于您的域,您应该努力使域看起来只有一种模型。这可以通过不同的方式来完成:

1) 让您的 ICustomerRepository(一个接口契约,其作用类似于针对对象集合)由使用子系统中的 Web 服务的基础设施相关存储库来实现。提示是您应该使用 GUID 作为密钥,以免发生密钥冲突。这种方法不会让您与其他实体的客户建立任何关系/关联。他们只能通过存储库(这是 Jimmy Nilsson 在他的书中使用的解决方案(http://jimmynilsson.com/blog /),不要用许多双向关系来收紧模型)。

2) 取决于您的用例如何针对/使用模型,但您可以创建一个应用程序范围的服务层,该服务层驻留在一个物理位置,但使用 CustomerService 、 CustomerProcuctService 和 ProductService 。为了防止域逻辑泄漏到应用程序层,可以将这些实体之间的一些协调封装在域事件处理程序中,以协调不同服务之间的某些事件。

3) 您还可以创建一个以其他子系统 CustomerGUID 作为键的 CustomerAdapter 类(它无法生成键,因为 Customer Webservice 可以控制它)。但是你可以在 Nhibernate 中映射它并在 CustomerProduct 和 CustomerAdapter 之间建立关系。但是当您映射 CustomerAdapter 时,您只会加载 GUID。然后确保您将使用 Spring.Net Windsor 或其他一些 DI 工具将 ICustomerAdapterService 注入到属性中。然后您不要在 Nhibernate 中映射 customerAdapter 的属性(如客户名称、地址等)。但是,当您从 CustomerAdapter 获取/读取 Adress 时,它将从 ICustomerAdapterService 获取它并设置所有其他值。
这不是推荐的解决方案,因为它会破坏一些 DDD 规则,例如在域模型中没有服务。但如果您从这个角度来看:它实际上可以被视为域服务,因为它解决了分布式域中的问题。然而,它包括与基础设施相关的东西,如 WCF 服务实现,因此服务实现应该在另一个基础设施层/程序集中

最简单的是解决方案 2 如果您可以处理客户实体只能由应用程序层中的服务访问的事实。
然而,该应用程序服务层可以成为两个子系统之间的良好反腐败层。今天有两个子系统可能是有原因的。
但是交互流的示例(不详细了解您的域的情况):

  • GUI 调用应用程序服务 CustomerProductService 方法 BuyNewProduct(CustomerDTO customer, ProductDTO newProduct)
  • CustomerProductService 将 ICustomerProductRepository 和 IProductRepository 注入到构造函数中。它还将有一个基础设施服务 ICustomerFacadeService(现在更改名称:-)),该服务被注入到 Property CustomerFacadeService 中。该服务的创建是由工厂完成的,该工厂有两个创建方法:Create() 和 CreateExtendishedWithCustomerService()。后者还将注入 CustomerServiceFacade
  • 方法 BuyNewProduct(...) 现在将组装 CustomerDTO 并使用 CustomerGUID 从 CustomerFacadeService 加载 Customer,该 Service 将调用另一个子系统中的 Web 服务。
  • 加载的客户将确保它确实存在,但现在我们使用 IProductRepository 加载产品。
  • 使用 CustomerGUID 值和产品实体,我们创建一个新的 CustomerProduct 实体(实际上只是产品和客户 GUID 之间的映射类)并通过 ICustomerProductRepository 保存
  • 它您可以调用其他基础设施服务向您的客户发送电子邮件,通知其可以访问新产品。或者,您可以在 CustomerProduct 实体中创建域事件,将该通知委托给已在 ctor 中注入 IEmailService 的事件处理程序(在应用程序服务层中)。然后,您就已经封装了在将新客户连接到产品时发送通知的领域知识。

希望这可以帮助您减轻域建模的痛苦。因为做DDD很痛苦。需要与同事、领域专家和自己在镜子前进行大量讨论:)这是正确的道路吗?
查看 DDDsample.net 中的领域事件或搜索 Udi Dahan 和领域事件。


我在这里写一个答案,更多空间:

关于交互流程示例中的CustomerAdadpter也称为CustomerFacadeService,这是我的观点:如何实现取决于您的应用程序。大多数用户案例是否会调用主系统来调用您的“云子系统”,这将具有良好的正常运行时间:-那么您可能不需要队列,并且将在云中拥有 WCF 服务。您的 CustomerFacadeService 将是一个服务包装器,它仅公开您的应用程序层所需的方法,并组装所有必要的 DTO 对象。
如果您的云系统也将回调到您的主系统,那么您需要将一些方法公开为服务。然后您可以选择将 NServiceBus 端点公开为 WCF 服务。这使您可以在不丢失信息的情况下关闭主系统。
但总是有很多但是...
如果您的基础技术人员想要安装修补程序/重新启动主系统的 Web 服务器,您当然需要在另一台计算机上拥有 WCF 服务。
如果您的客户在主系统关闭时等待响应,他们会等待多长时间?我想不会太长。
因此,我可以看到这样做的好处之一是,如果您有需要执行的批次/报告,并且如果系统的一部分发生故障,则一旦系统再次启动,报告将继续。

以下是公开为 WCF 服务的 NServiceBus 的一些示例。但我没有这方面的经验,只是知道“这是可以做到的”。
http://docs.pspecial.net/nservicebus/architecture/nservicebus-and-wcf

hi I haven't been in your situation before, but I have designing domains that communicate with other subsystems.
I do not have the whole picture, but it seems like the customer entity is more isolated from the others, CustomerProduct and Product. So am I guessing correct that you will present the model in a common GUI but its only the datasource that are separated?

First you can solve this by different ways and you should also ask yourself about non-functional requirements such as maintenance, uptime and support. Will both systems always be up and running simultaneously or will it happened that you take on system down. The clue I'm fishing for is should you communicate sync or async (message queuing?) with subsystems. This can be achieved by using NServiceBus.

But to focus on your Domain, you should go for making the Domain look like it only has one model. This can be accomplished in different ways:

1) Have your ICustomerRepository (an interface contract that acts like is working against a collection of objects) be implemented by a infrastructure related repository that consume your web service in your subsystem. A hint is that you should use GUID as keys so keyconfilcts occur. This approach will not let you have any relationships/associations to customer from your other entities. They will but only through the repository (This a solution that Jimmy Nilsson uses in his book (http://jimmynilsson.com/blog/) to not tighten the model with to many bidirectional relationships).

2) Depends how your use cases will target/use the model, but you can create a application wide service layer that resides at one physical place but uses CustomerService and CustomerProcuctService and ProductService. To prevent that domain logic will leak into application layer some of the coordination between these entites can be encapsulated in a domain event handlers that coordinate some events between different services.

3) you can also create a CustomerAdapter class that have the other subsystems CustomerGUID as a key (it cannot generate keys since Customer webservice have control of that). But you can map it in Nhibernate and have relationsship between CustomerProduct and CustomerAdapter. But when you Map CustomerAdapter you will only load the GUID. Then make sure you will have a ICustomerAdapterService injected into a property using Spring.Net Windsor or some other DI tool. Then you to not map properties (like customername, adress etc) for customerAdapter in Nhibernate. But when you get/read Adress from CustomerAdapter it will get it from ICustomerAdapterService and set all other values as well.
This is not a recommended solution since it will break some DDD rules, like not having services in domain model. But if you see it from this perspective: it actually can be considered a Domain Service since it solves problem within your distributed domain. However it includes infrastructure related things like a WCF service implementation and therefore should the service implementation be in another infrastructure layer/assembly

Most simple is the solution 2 If you can handle the fact that Customer Entity will be accessed only by a Service in application layer.
However this application serviclayer can be a good anticorruption layer between the two subsystems. There is probably a reason why you have two subsystems today.
But an example of interaction flow (with no detailed knowledge of how your domain is):

  • GUI calls Application Service CustomerProductService method BuyNewProduct(CustomerDTO customer, ProductDTO newProduct)
  • CustomerProductService have ICustomerProductRepository and IProductRepository injected into constructor. It will also have a infrastructure Service ICustomerFacadeService (change name now :-)) that is injected into a Property CustomerFacadeService. The creation of this service is done by a factory that have two creation methods, Create() and CreateExtendendedWithCustomerService(). The later one will also inject CustomerServiceFacade
  • The method BuyNewProduct(...) will now Assemble the CustomerDTO and use the CustomerGUID to load Customer from CustomerFacadeService that will call the web service in the other subsystem.
  • The loaded customer will ensure that it actually exists but now we load the Product with IProductRepository
  • With both CustomerGUID value and Product Entity we create a new CustomerProduct entity (which is actually just a mapping class between Products and Customer GUID's) and save it through ICustomerProductRepository
  • Now you can call another infrastructure service to send an email to your customer that will be notified that it has access to the new product. Or you can create Domain events in CustomerProduct entity that delegates this notification to en eventhandler (in application service layer) that has the IEmailService injected in ctor. Then you have incapsulted the domain knowledge of sending notifications when you connect a new customer to a product.

Hope this help you in modelling your domain with less pain. Because its painful to do DDD. Requires a lot discussions with colleagues, domain experts and yourself in front of the mirror :) Is this the right path?
Look at the DDDsample.net for Domain Events or search for Udi Dahan and domain events.


I write an answer here, more space:

Regarding CustomerAdadpter also refered as CustomerFacadeService in the interaction flow example here is my opinion: How to implement depends of your application. Will most usercase be calling mainsystem calling your "cloud-subsystem" which will have a good uptime: -Then you maybe do not need a queue and will have a WCF service in the cloud. Your CustomerFacadeService will be a service Wrapper that just exposes the method your application layer needs and also assemble all necessary DTO objects.
If your cloud system will also call back to your mainsystem then you need to expose some of your methods as a service. THEN you have the option to expose a NServiceBus endpoint as a WCF service. This gives you the possibility to take down the mainsystem without loosing information.
But there is always a lot of buts...
You need of course to have the WCF service on another machine if your infra-tech guys want to install hotfixes/reboot main system's web server.
If you have client's waiting for an response while main system is down, how long will they wait? Not too long I guess.
So one scenario I can see benefits of this is if you have batches/reports that need to be carried out, and if one part of the system is down, the reporting will continue once it's up again.

Here is some example of NServiceBus exposed as a WCF service. But I have no experience in doing exactly that, just the knowledge of "it can be done".
http://docs.particular.net/nservicebus/architecture/nservicebus-and-wcf

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文