FindAndModify在哪里适合CQRS?

时间:2015-03-07 23:38:57

标签: c# mongodb cqrs

在我当前的应用程序中,我对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电话(或任何其他类似的问题,如此查询)在哪里适合?

3 个答案:

答案 0 :(得分:3)

这将是固执己见,但这是我的看法:

CQRS命令通常应对单个聚合实体采取某些特定操作。

命令示例:

  • ChangePersonName
  • PlaceOrder
  • DeleteAccount

如果在执行命令处理程序实现时需要数据,它应该来自严格按其文档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

我希望这很有用。