我正在构建图书馆应用程序。假设我们有一个要求,让图书馆中的注册人到借书 书一段默认时间(4周)。
我开始使用名为Loan的AggregateRoot使用以下代码对域进行建模:
public class Loan : AggregateRoot<long>
{
public static int DefaultLoanPeriodInDays = 30;
private readonly long _bookId;
private readonly long _userId;
private readonly DateTime _endDate;
private bool _active;
private Book _book;
private RegisteredLibraryUser _user;
public Book Book => _book;
public RegisteredLibraryUser User => _user;
public DateTime EndDate => _endDate;
public bool Active => _active;
private Loan(long bookId, long userId, DateTime endDate)
{
_bookId = bookId;
_userId = userId;
_endDate = endDate;
_active = true;
}
public static Loan Create(long bookId, long userId)
{
var endDate = DateTime.UtcNow.AddDays(DefaultLoanPeriodInDays);
var loan = new Loan(bookId, userId, endDate);
loan.Book.Borrow();
loan.AddDomainEvent(new LoanCreatedEvent(bookId, userId, endDate));
return loan;
}
public void EndLoan()
{
if (!Active)
throw new LoanNotActiveException(Id);
_active = false;
_book.Return();
AddDomainEvent(new LoanFinishedEvent(Id));
}
}
而且我的Book实体看起来像这样:
public class Book : Entity<long>
{
private BookInformation _bookInformation;
private bool _inStock;
public BookInformation BookInformation => _bookInformation;
public bool InStock => _inStock;
private Book(BookInformation bookInformation)
{
_bookInformation = bookInformation;
_inStock = true;
}
public static Book Create(string title, string author, string subject, string isbn)
{
var bookInformation = new BookInformation(title, author, subject, isbn);
var book = new Book(bookInformation);
book.AddDomainEvent(new BookCreatedEvent(bookInformation));
return book;
}
public void Borrow()
{
if (!InStock)
throw new BookAlreadyBorrowedException();
_inStock = false;
AddDomainEvent(new BookBorrowedEvent(Id));
}
public void Return()
{
if (InStock)
throw new BookNotBorrowedException(Id);
_inStock = true;
AddDomainEvent(new BookReturnedBackEvent(Id, DateTime.UtcNow));
}
}
您可以看到,我正在使用静态工厂方法来创建我的贷款汇总根,在此我要传递借书的身份和要借书的用户身份。我应该在这里传递对这些对象(书和用户)的引用,而不是id吗?哪种方法更好?如您所见,我的Book实体还有一个属性,该属性指示一本书的可用性(InStock
属性)。我是否应该在下一个用例中,例如在LoadCreatedEvent
的处理程序中更新此属性?还是应该在我的AggregateRoot中更新它?如果应该在我的汇总表中对其进行更新,则应该传递整本书的参考文献,而不仅仅是传递一个ID,以便调用它的方法_book.Borrow()
。我被困在这一点上是因为我想用DDD方法做的很正确。还是我从错误的角度开始做这件事,而我正在丢失某些东西或以错误的方式思考?
DomainEvents
是在同一域中处理的内存中事件。
您一起提交或回滚整个“事务”。将域事件视为DTO,它需要保存与域中刚发生的事情有关的所有信息。因此,只要您拥有该信息,我认为如果您传递Id或整个object
都没有关系。
我会在域事件中传递id
,尽管该信息足以将信息传递给DomainEventHandler
。
另外,请参考Microsoft Docs中类似情况的示例,其中它们仅传递UserId
和CardTypeId
以及Domain事件中的所有其他相关信息。
public class OrderStartedDomainEvent : INotification { public string UserId { get; } public int CardTypeId { get; } public string CardNumber { get; } public string CardSecurityNumber { get; } public string CardHolderName { get; } public DateTime CardExpiration { get; } public Order Order { get; } public OrderStartedDomainEvent(Order order, int cardTypeId, string cardNumber, string cardSecurityNumber, string cardHolderName, DateTime cardExpiration) { Order = order; CardTypeId = cardTypeId; CardNumber = cardNumber; CardSecurityNumber = cardSecurityNumber; CardHolderName = cardHolderName; CardExpiration = cardExpiration; } }