Reputation:
I am trying out DDD-style architecture with asp.net core but I'm having trouble understanding how to Update a aggregate roots child-entites after its created.
I have a order-class which has a read-only list of OrderLines. These orderlines can be updated or removed from the order. The order will always be edited in the frontend in a single transaction(post to API).
I have made methods for this on the order aggregate, but it feels like the logic is in the wrong place. Is this the correct way to update/delete child-entites in DDD?
Since the Order will come in to a API in a PUT-fashion I check if any items that are on the entity from the DB are not in the incoming data. If not, I remove them. If they are, I update them.
Does this belong in a service-class instead? What is the best practice in DDD?
public class Order : BaseEntity, IAggregateRoot
{
public Order(List<OrderItem> items, Address shippingAddress, int customerId)
{
ShipToAddress = shippingAddress ?? throw new Exception("Can not be null");
_orderItems = items ?? throw new Exception("Can not be null");
CustomerId = customerId;
Status = OrderStatus.Processing;
}
private readonly List<OrderItem> _orderItems = new List<OrderItem>();
public IReadOnlyCollection<OrderItem> OrderItems => _orderItems.AsReadOnly();
public void AddOrUpdateOrderItem(ProductOrdered itemOrdered, decimal unitPrice, int units, DateTime deliverDate, int orderItemId)
{
var existingOrderLine = _orderItems.Where(o => o.Id == orderItemId)
.SingleOrDefault();
if (existingOrderLine != null)
{
existingOrderLine.Update(itemOrdered, unitPrice, units, deliverDate);
}
else
{
//add validated new order item
var orderItem = new OrderItem(itemOrdered, unitPrice, units, deliverDate);
_orderItems.Add(orderItem);
}
}
public void RemoveOrderLines(List<int> orderItemIds)
{
foreach (var item in _orderItems.ToList())
{
var containsItem = orderItemIds.Any(newOrderLine => newOrderLine == item.Id);
if (!containsItem)
{
_orderItems.Remove(item);
}
}
}
}
OrderLine:
public class OrderItem : BaseEntity
{
public ProductOrdered ItemOrdered { get; private set; }
public decimal UnitPrice { get; private set; }
public int Units { get; private set; }
public DateTime DeliveryDate { get; set; }
public OrderLineStatus OrderLineStatus { get; set; }
private OrderItem()
{
// required by EF
}
public OrderItem(ProductOrdered itemOrdered, decimal unitPrice, int units, DateTime deliverDate)
{
ItemOrdered = itemOrdered;
UnitPrice = unitPrice;
Units = units;
DeliveryDate = deliverDate;
OrderLineStatus = OrderLineStatus.Waiting;
}
public void Update(ProductOrdered itemOrdered, decimal unitPrice, int units, DateTime deliverDate)
{
ItemOrdered = itemOrdered;
UnitPrice = unitPrice;
Units = units;
DeliveryDate = deliverDate;
}
}
Upvotes: 0
Views: 2418
Reputation: 1210
I have made methods for this on the order aggregate, but it feels like the logic is in the wrong place. Is this the correct way to update/delete child-entites in DDD?
Yes. I just don't like that 2 separate use cases are defined in one. I would do Add in separate method and Update in another. Regarding to Put endpoint. Consider using Task-Based UI. It fits DDD much better than CRUD based put operation. So, define commands - AddLineItemCommand, UpdateLineItemCommand, RemoveLineItemCommand and different POST operations for them. Treat each use case differently.
Upvotes: 1