DDD,库应用场景中的汇总根和实体

问题描述 投票:0回答:1

我正在构建图书馆应用程序。假设我们有一个要求,让图书馆中的注册人借书 一段默认时间(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方法做的很正确。还是我从错误的角度开始做这件事,而我正在丢失某些东西或以错误的方式思考?

oop domain-driven-design aggregateroot clean-architecture
1个回答
0
投票

DomainEvents是在同一域中处理的内存中事件。

您一起提交或回滚整个“事务”。将域事件视为DTO,它需要保存与域中刚发生的事情有关的所有信息。因此,只要您拥有该信息,我认为如果您传递Id或整个object都没有关系。

我会在域事件中传递id,尽管该信息足以将信息传递给DomainEventHandler

另外,请参考Microsoft Docs中类似情况的示例,其中它们仅传递UserIdCardTypeId以及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;
} }
© www.soinside.com 2019 - 2024. All rights reserved.