聚合做出业务决策所需的任何信息都应存储为聚合状态的一部分。因此,当收到将钱存入客户账户的命令时,您应该已经拥有该客户的当前/更新状态,其中可以包含他们每个账户的当前余额。
我还建议聚合永远不应该去读取模型来提取信息。根据您要实现的目标,您可以使用读取模型中的其他详细信息来丰富命令(其中状态不是关键的),但聚合本身应该从它自己的已知状态中提取。
编辑
重新阅读问题后,我意识到您正在谈论跨多个聚合跟踪状态。这属于传奇的领域。您可以创建一个 saga 来跟踪进入前 10% 所需的阈值。因此,每当客户进行存款时,传奇都可以跟踪他们在排名中的位置。如果该客户端跨越线程,您可以从 saga 发布命令以指示它们满足所需的条件。
在您的情况下,您的 saga 可能会跟踪所有存款的总金额,因此当进行存款时,可以决定客户现在是否位于前 10%。您可能想问自己的其他问题……如果客户存入 X 美元,并立即将 Y 美元降回门槛以下;应该发生什么?等等。
非常粗糙的聚合/传奇处理方法......
public class Client : Aggregate
{
public void Handle(DepositMoney command)
{
// What if the account is not known? Has insufficient funds? Is locked? etc...
// Track the minimum amount of state required to make whatever choice is required.
var account = State.Accounts[command.AccountId];
// Balance here would reflect a point in time, and should not be directly persisted to the read model;
// use an atomic update to increment the balance for the read-model in your denormalizer.
Raise(new MoneyDeposited { Amount = command.Amount, Balance = account.Balance + command.Amount });
}
public void Handle(ElevateClientStatus command)
{
// you are now a VIP... raise event to update state accordingly...
}
}
public class TopClientSaga : Saga
{
public void Handle(MoneyDeposited e)
{
// Increment the total deposits... sagas need to be thread-safe (i.e., locked while state is changing).
State.TotalDeposits += e.Amount;
//TODO: Check if client is already a VIP; if yes, nothing needs to happen...
// Depositing money itself changes the 10% threshold; what happens to clients that are no longer in the top 10%?
if (e.Balance > State.TotalDeposits * 0.10)
{
// you are a top 10% client... publish some command to do whatever needs to be done.
Publish(new ElevateClientStatus { ClientId = e.ClientId, ... });
}
}
// handle withdrawls, money tranfers etc?
}