我正在使用事件源实现 CQRS 模式,我正在使用 NServiceBus、NEventStore 和 NES(NSB 和 NEventStore 之间的连接)。
我的应用程序将定期检查网络服务是否有任何要下载和处理的文件。当找到一个文件时,一个命令 (DownloadFile) 被发送到总线,并由 FileCommandHandler 接收,它创建一个新的聚合根 (File) 并处理消息。
现在在(文件聚合根)中,我必须检查文件的内容是否与任何其他文件内容不匹配(因为 Web 服务保证只有文件名是唯一的,并且内容可能会以不同的名称重复) ,通过对其进行散列并与散列内容列表进行比较。
问题是我必须在哪里保存哈希码列表?是否允许查询读取模型?
public class File : AggregateBase
{
public File(DownloadFile cmd, IFileService fileDownloadService, IClaimSerializerService serializerService, IBus bus)
: this()
{
// code to download the file content, deserialize it, and publish an event.
}
}
public class FileCommandHandler : IHandleMessages<DownloadFile>, IHandleMessages<ExtractFile>
{
public void Handle(DownloadFile command)
{
//for example, is it possible to do this (honestly, I feel it is not, since read model should always considered stale !)
var file = readModelContext.GetFileByHashCode (Hash(command.FileContent));
if (file != null)
throw new Exception ("File content matched with another already downloaded file");
// Since there is no way to query the event source for file content like:
// eventSourceRepository.Find<File>(c=>c.HashCode == Hash(command.FileContent));
}
}
最佳答案
似乎您正在寻找重复数据删除。
您的命令端是您希望事情保持一致的地方。查询将始终让您对竞争条件持开放态度。因此,我不会运行查询,而是反转逻辑并将散列实际写入数据库表(任何具有 ACID 保证的数据库)。如果此写入成功,则处理该文件。如果哈希写入失败,则跳过处理。
将此逻辑放入处理程序是没有意义的,因为在失败的情况下重试消息(即多次存储散列)不会使其成功。您最终还会在错误 q 中收到重复文件的消息。
重复数据删除逻辑的一个好地方可能是在您的 Web 服务客户端中。一些伪逻辑
NServiceBus 网关 here 中的一些示例重复数据删除代码
编辑:
查看他们的代码,我实际上认为
session.Get<DeduplicationMessage>
是不必要的。 session.Save(gatewayMessage);
应该就够了,是一致性边界。只有在失败率很高的情况下执行查询才有意义,这意味着您有很多重复的内容文件。如果 99% 以上的插入成功,则确实可以将重复项视为异常。
关于c# - 查询重复聚合根属性的写入模型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23215983/