我正在尝试用C#和ERP对一个ERP系统的运输模块进行建模。该服务负责管理客户的皮卡和公司所有的卡车交付.客户皮卡包含订单列表,卡车包含停靠站列表,而这些站包含订单列表。
用于管理皮卡和卡车的主要接口是通过一个基于REST的api。通过服务总线队列从订购模块接收订单创建/更新/取消事件。
我们使用关系数据库( Server)存储各个实体。我的问题实际上是如何建模这些不同的聚合根/实体/值对象/域服务/域事件以及支持它们的数据库表。
不过,为了执行卡车的业务规则,事情变得有点有趣了。如果将订单添加到卡车上,则需要考虑所有其他订单的总重和数量,如果订单将导致卡车超过规定的阈值,则应返回错误。如果收到已与卡车关联的订单的订单更新,并且该订单将导致卡车超过允许的阈值,则需要发射警报,并且在问题解决之前不能将卡车标记为正在运输中。
如有需要,乐意提供更多的澄清。任何想法都很感激。
发布于 2020-03-28 01:46:17
作为一般经验规则(尤其是考虑到加载整个卡车的效率),您希望将聚合保持在较小的范围内,并且只更新一个事务中的单个聚合。这确实意味着跨越多个聚合的业务规则最终只能是一致的,但这通常不会导致任何实际问题。
在此基础上,你可能会考虑把你目前的设计翻个底朝天:而不是那些装有订单列表的皮卡和卡车站,而是创建一个一流的集合(比如PickupOrder和TruckStopOrder)来模拟订单与皮卡或卡车站的关联。
Order上下文处理UpdateOrderCommand:
Order聚合。OrderUpdated事件。卡车上下文处理OrderUpdated事件:
TruckStopOrder聚合。TruckStopOrderUpdated事件。卡车上下文处理TruckStopOrderUpdated事件:
Truck集合的总体积/重量。要向卡车添加订单的UI可以使用来自Truck聚合的缓存信息来显示警告,如果卡车已经满了。在并发系统中,这永远不能保证是一致的,因为其他用户可能同时更新卡车。
发布于 2020-03-29 05:59:51

我会用这个域模型..。我通常将业务需求分解为核心操作。一旦我确定了这些核心操作,我就会识别出承载这些操作的子域。
注意,我更喜欢首先识别操作,因为为了使这些操作成功,我更容易识别需要哪些类型的操作。
仅仅因为OOP语言(如C#或Java )是通用的,并不意味着它们是对业务域建模的理想语言。因此,我真诚地相信静态类型的FP语言是一种自然的适合于业务域建模的语言,因为它的语法越少,信息密度越高。
关于数据持久性,我不认为关系数据库是理想的。我将使用事件存储(即不可变数据库),以便不能覆盖或删除数据。毕竟,这个域是关于对历史域事件的操作,这些事件永远不应该被更新或删除(只是附加的)。
我提供了以下模型,给出了域的描述:
namespace CustomerOrder
open Shared
open Language
module Operations =
type PlaceOrder = PlaceOrderSubmission -> AsyncResult<unit,Error>
type ChangeAcquisition = ChangeAcquisitionSubmission -> AsyncResult<unit,Error>module Language
open Shared
type AuthenticatedCustomer = TODO
type AcquisitionType = string // Ex: CustomerPickup | TruckDelivery
type PlaceOrderSubmission = {
AuthenticatedCustomer : AuthenticatedCustomer
Order : Order
OrderRequestType : AcquisitionType
}
type ChangeAcquisitionSubmission = {
OrderSubmission : PlaceOrderSubmission
NewAcquisitionRequest : AcquisitionType
}namespace OrderDispatcher
open Shared
open Language
module Operations =
type AvailableTruckers = AvailableTruckersRequest -> AsyncResult<TruckersOpen,Error>
type DispatchTrucker = DispatchTruckerSubmission -> AsyncResult<unit,Error>
type CancelledOrder = OrderCancellationSubmission -> AsyncResult<OrderCancellationReceipt,Error>
type ChangeOrderAcquisition = OrderAcquisitionChangeSubmission -> AsyncResult<UnstartedOrder,Error>module Language
open Shared
type TruckerId = string
type Trucker = {
TruckerId : TruckerId
}
type DispatchTruckerSubmission = {
Trucker : Trucker
Order : Order
}
type AvailableTruckersRequest = {
Order : Order
}namespace Trucker
open Shared
open Language
module Common =
type QueryUnstartedOrders = AuthenticatedTrucker -> AsyncResult<UnstartedOrders,Error>
module NewOrderPending =
type AcceptOrderRequest = OrderResponseSubmission -> AsyncResult<unit,Error>
type DeclineOrderRequest = OrderResponseSubmission -> AsyncResult<unit,Error>
type ForfeitOrderRequest = OrderResponseSubmission -> AsyncResult<unit,Error>
module AcceptedOrder =
type CancelAcceptance = CancellableOrder -> AsyncResult<unit,Error>
type StartInTransit = OrderProduced -> AsyncResult<InTransitToPickupTrucker,Error>
type InTransitToPickup = InTransitToPickupTrucker -> AsyncResult<IntransitToPickupOrder ,Error>
//----------------------------------------------------------------------------------------
// Handle change of how order is acquired (i.e. pickup or delivery)
//----------------------------------------------------------------------------------------
type MyDelegate = delegate of obj * OrderCancelled -> unit
type IOrderCancelled =
[<CLIEvent>]
abstract member OrderCancelled : IEvent<MyDelegate, OrderCancelled>
type IncomingNotification () =
let orderCancelled = new Event<MyDelegate, OrderCancelled> ()
interface IOrderCancelled with
[<CLIEvent>]
member x.OrderCancelled = orderCancelled.Publish
//----------------------------------------------------------------------------------------
module InTransitToDropoff =
type CancelAcceptance = InTransitToDropoffTrucker -> AsyncResult<OrderCancellationReceipt,Error>
type InTransitToDropoff = InTransitToDropoffTrucker -> AsyncResult<IntransitToDropoffOrder ,Error>
type ClaimDelivered = InTransitToDropoffTrucker -> AsyncResult<OrderClosed ,Error>
module OrdersCompleted =
type CloseTruck = CloseTruckSubmission -> AsyncResult<ClosedTruckReceipt,Error>module rec Language
open Shared
type TruckerStatus =
| Open of OpenedTrucker
| InTransit of InTransitTrucker
| Completed of CompletedTrucker
type AcceptedOrder = {
Trucker : OpenedTrucker
}
type IntransitToPickupOrder = {
Trucker : InTransitTrucker
}
type IntransitToDropoffOrder = {
Trucker : InTransitTrucker
}
type CompletedOrder = {
Trucker : CompletedTrucker
}
type OrderResponseSubmission = {
OpenedTrucker : OpenedTrucker
UnstartedOrder : UnstartedOrder
Response : Response
}
type InTransitTrucker = {
Trucker : AuthenticatedTrucker
CurrentOrder : OrderProduced
OrdersProduced : OrderProduced seq
OrdersClosed : OrderProduced seq
}
type InTransitToPickupTrucker = {
Trucker : AuthenticatedTrucker
Order : OrderInTransit
}
type InTransitToDropoffTrucker = {
Trucker : AuthenticatedTrucker
Order : OrderInTransit
}
type CompletedTrucker = {
Trucker : AuthenticatedTrucker
OrdersClosed : OrderProduced seq
}
type ArrivedAtDropoffSubmission = {
Trucker : InTransitTrucker
}
type CancellableOrder =
| OpenedTrucker of OpenedTrucker
| InTransitTrucker of InTransitTrucker
type CloseTruckSubmission = {
OrdersClosed : OrderClosed seq
}
type ClosedTruckReceipt = {
OrdersClosed : OrderClosed seq
}module Shared
type AsyncResult<'T,'error> = Async<Result<'T,'error>>
type Error = string
type OrderId = string
type TruckerId = string
type CustomerId = string
type ItemId = string
type Name = string
type Description = string
type Response = string
type Address = string
type Weight = float
type feet = float
type AcquisitionType = string
type CancellationId = string
type OrderStatus = string
type Dimensions = {
Length : feet
Width : feet
Height : feet
}
type AuthenticatedTrucker = {
TruckerId : TruckerId
}
type OpenedTrucker = {
Trucker : AuthenticatedTrucker
}
type Item = {
ItemId : ItemId
Name : Name
Description : Description
Weight : Weight
Dimensions : Dimensions
}
type ItemQty = {
Item : Item
Qty : int
}
type ItemQtys = ItemQty seq
type Pickup = {
Address : Address
ItemQtys : ItemQtys
}
type Customer = {
CustomerId : CustomerId
Address : Address
}
type Order = {
OrderId : OrderId
Customer : Customer
Pickup : Pickup
Status : OrderStatus
}
type OrderProduced = {
Order : Order
}
type OrderInTransit = {
OrderProduced : OrderProduced
}
type OrderClosed = {
OrderInTransit : OrderInTransit
}
type OrderCancelled = {
Order : Order
}
type OrderCancellationSubmission = {
Order : Order
Reason : string
}
type OrderCancellationReceipt = {
CancellationId : CancellationId
Order : Order
Reason : string
}
type OrderAcquisitionChangeSubmission = {
Order : OrderCancellationReceipt
AcquisitionType : AcquisitionType
}
type UnstartedOrder = { Order: Order }
type UnstartedOrders = UnstartedOrder seqhttps://softwareengineering.stackexchange.com/questions/407064
复制相似问题