在我当前的应用程序中,我对MongoDB服务器进行了以下MongoDB FindAndModify
调用
public static TEntity PeekForRemoveSync<TEntity>(this MongoCollection<TEntity> collection, string reason)
where TEntity : class, IEntity, IUpdatesTrackable, ISyncable, IDeletable, IApprovable
{
if (reason == null)
{
throw new ArgumentNullException(nameof(reason));
}
IMongoQuery query = Query.And(
Query<TEntity>.EQ(e => e.SyncInfo.IsDirty, true),
Query<TEntity>.NE(e => e.Deletion, null),
Query<TEntity>.NE(e => e.Approval, null),
Query<TEntity>.EQ(e => e.SyncInfo.HumanInvestigateFlag, null),
Query.Or(
Query<TEntity>.EQ(e => e.SyncInfo.IsUpdateInProgress, false),
Query<TEntity>.LT(e => e.SyncInfo.UpdateStartInfo.OccuredOn, DateTime.UtcNow.AddSeconds(-SyncConstants.PeekExpireTimeInSeconds))
),
Query<TEntity>.LTE(e => e.SyncInfo.PeekedCount, MaxPeekedCount)
);
return PeekForSync(collection, query, reason);
}
private static TEntity PeekForSync<TEntity>(this MongoCollection<TEntity> collection, IMongoQuery query, string reason)
where TEntity : class, IEntity, IUpdatesTrackable, ISyncable, IDeletable
{
UpdateBuilder<TEntity> update = Update<TEntity>
.Inc(e => e.SyncInfo.PeekedCount, 1)
.Set(e => e.SyncInfo.UpdateStartInfo, new OccuranceWithReason(reason))
.Set(e => e.SyncInfo.IsUpdateInProgress, true);
SortByBuilder<TEntity> sort = SortBy<TEntity>.Descending(e => e.LastUpdatedOn);
FindAndModifyArgs fmArgs = new FindAndModifyArgs
{
Query = query,
Update = update,
SortBy = sort,
VersionReturned = FindAndModifyDocumentVersion.Modified
};
FindAndModifyResult result = collection.FindAndModify(fmArgs);
return result.ModifiedDocument != null
? result.GetModifiedDocumentAs<TEntity>()
: null;
}
我是否正在使用MongoDB重新构建另一个队列系统?这不是我的意图,而是它的意思。只需忽略那里的业务逻辑。
在CQRS中,查询和命令意味着以下(我相信):
命令:更改系统状态,不返回任何值。
查询:不会更改系统状态并返回一些值。
如果是这种情况,我上面的FindAndModify
电话(或任何其他类似的问题,如此查询)在哪里适合?
答案 0 :(得分:3)
这将是固执己见,但这是我的看法:
CQRS命令通常应对单个聚合实体采取某些特定操作。
命令示例:
如果在执行命令处理程序实现时需要数据,它应该来自严格按其文档ID找到的文档。 (或Mongo中的ObjectId
)
在某些文档数据库中,使用ID之外的其他内容进行查询是最终的一致操作。如果您依赖查询的结果来决定要采取的操作,那么当索引过时时您可能会丢失一些项目。您怎么知道该命令真正完成了所有数据?你不会。
如果查询结果确实完全一致(它可能在Mongo中,我并非100%确定),即便如此,您也会遇到计时问题。您可能打算对与查询匹配的所有数据执行操作,但可能会在几毫秒后插入与查询匹配的新数据。由于操作范围不受特定文档(或一组文档)的限制,因此您无法确定是否真的已完成。
一般来说,我说在CQRS命令中执行查询(除文档ID以外的任何内容)不是一个好主意。
FindAndModify
看起来像用于修补。您可能确实需要偶尔这样做,但它不会与CQRS模式一致。我会保留它用于维护任务 - 在系统的主要CQRS部分之外。
答案 1 :(得分:1)
我不确定我的问题是否正确,所以这就是我理解的答案:
我希望将CQRS视为并发模式和数据模型指南的组合。
数据模型指南是更明显的指导,毕竟,您现在使用的是多个模型。在非CQRS场景中,可能有(未完成的)订单或购物车的以下对象:
{ items : [ { 'sku' : '235423', 'qty' : 3, 'price' : 4.34, ... }, ... ],
orderStatus : 'in_cart',
customerId : null,
...
}
现在,更新该模型本身很容易,但CQRS告诉您不要这样做。假设我想添加产品&#39; 1234&#39;到那个车。当然,我可以回复整个新车。但这都是低效的(我需要的只是信息&#39;我想将1个产品1234添加到购物车X&#39;),并且令人恼火,因为无论如何,服务器必须忽略总价格。
然而,我的核心是,CQRS主要是并发方案 - 至少与Event Sourcing结合使用。通过记录谁更改了什么时间,我们可以集中负责应用更改的代码,处理冲突,允许撤消/重做和保留审计日志,所有这些都在同一时间。当然,这是以最终的一致性为代价的,但概念是an object that has many concurrent writers doesn't have a well-defined 'current' state anyway(至少我是如何理解它的。)
此外,再次查看该购物车,也许更新模型并不是一件轻而易举的事,因为购物车可能代表对购物车中物品的锁定(至少对于冲突的可能性很高,例如闪购 - 如果购物车中的产品,我想知道我实际上可以购买它,比如10分钟)。如果没有命令对象,则必须分析文档从状态1转换到状态2的方式以及更改的确切方式,以及不释放任何现有锁,但可能获取新锁(或释放一个并获取新锁)。 / p>
相反,您可以发送AddToCartCommand
:
{ item : { 'sku' : '4242342', 'qty' : 4 },
cartId : 53543 }
如果该产品销售太快,它不会受到伤害,因为我们并未放弃购物篮 - 添加到购物车命令失败,但购物车的状态保持完全不变。如果站点处于高负载且买方添加了另一个产品,则该命令可能会成功。使用传统的请求/响应模式,如果可能的话,这将是不容易的。
这可能不是最好的例子,但假设购物车同时由多个用户填充,那么简单的最后一次写入会赢得&#39;并发(没有锁定)或乐观的外观(错误:其他人在其间更改了文档)会有问题。
在CQRS中,由于我们没有立即进行更新,因此我们可以避开RPC(一种方法调用&#39;告诉我立即发生的事情)和过度客户端特定的接口。此外,与RPC与REST不同,CQRS至少更深层次。虽然它肯定会对客户端代码产生很大影响,但它对服务器处理信息的方式产生了巨大影响,它以异步,可能分布的方式甚至可能涉及完全不同的数据存储(因为模型总是不同)。
在任何情况下,我认为您发布的代码可能是两个模型进行通信的点,即必须应用更改的位置,这可能很棘手。首先,这需要(分布式)事务,因此需要进行大量锁定并且锁定需要原子更新,因此在这种情况下findAndModify
似乎是必需的。
我不确定偷看的确切行为,但对我而言,您的代码看起来像是试图对文档进行短暂锁定(来自IsDirty : true
和{{1标准)。
总之,我说CQRS是网络的异步。
答案 2 :(得分:0)
FindAndModify操作通常在以数据为中心的应用程序中找到。但是,有一些方法可以找到FindAndModify&#39;可能会找到CQRS应用程序的方法。
在您的域中,FindAndModify可能是一个合法的,如果命名错误的命令。您将命令路由到执行&#39; FindAndModify&#39;的单个聚合。只是要明确这是一个单一的聚合。我还假设&#39; FindAndModify&#39;意味着你的域名。 另一个地方可能在事件处理程序中。不难想象某种形式的NameChanged类型事件。这可能会触发FindAndModify样式响应。
我假设您已经了解了CQRS和事件采购。如果没有,并且您正在寻找一个典型的CQRS ES应用程序如何组合的良好概述,请查看我的博客文章:CQRS – A Step-by-Step Guide to the Flow of a typical Application
我希望这很有用。