C# 如何将现有类转换为包含事件的DDD聚合?

C# 如何将现有类转换为包含事件的DDD聚合?,c#,microservices,domain-driven-design,azure-service-fabric,event-sourcing,C#,Microservices,Domain Driven Design,Azure Service Fabric,Event Sourcing,下面有一个类,用于执行买卖订阅的交易操作。我想转换这个类,以便它可以在使用事件源和可能的CQR的微服务中使用。我的想法是,这将生活在一个服务结构的演员里面,这个类将完全在记忆中 public class OrderBook { public const int ScaleFactor = 10_000; private long _orderId = 1; public OrderBook() { Limits = new RankedSet&l

下面有一个类,用于执行买卖订阅的交易操作。我想转换这个类,以便它可以在使用事件源和可能的CQR的微服务中使用。我的想法是,这将生活在一个服务结构的演员里面,这个类将完全在记忆中

public class OrderBook
{
    public const int ScaleFactor = 10_000;
    private long _orderId = 1;

    public OrderBook()
    {
        Limits = new RankedSet<Limit>(new LimitPriceComparer()) { new Limit { Price = 1 * ScaleFactor } };
        Subscriptions = new Dictionary<long, Subscription>();
        Orders = new Dictionary<long, Order>();
    }

    private RankedSet<Limit> Limits { get; }
    private IDictionary<long, Subscription> Subscriptions { get; }
    private IDictionary<long, Order> Orders { get; }

    public Order Ask(long userId, long price, int shares)
    {
        if (userId <= 0 || price <= 0 || shares <= 0)
        {
            // TODO: Return a message or something.
            return null;
        }

        price = price * ScaleFactor;

        // Get the users subscription.
        if (!Subscriptions.TryGetValue(userId, out Subscription subscription))
        {
            // TODO: Return a message or something.
            return null;
        }

        var index = Limits.Count - 1;
        var originalShares = shares;
        while (index >= 0 && shares > 0)
        {
            var currentLimit = Limits.ElementAt(index);
            if (currentLimit.Price < price)
            {
                break;
            }

            Order order = currentLimit.BidHead;
            while (order != null && shares > 0)
            {
                if (order.Subscription.UserId == userId)
                {
                    if (order.Next == null)
                    {
                        break;
                    }
                    else
                    {
                        order = order.Next;
                    }
                }

                // Always assume the bid will have a subscription even if it's empty.
                if (order.Shares >= shares)
                {
                    order.Subscription.Owned += shares;
                    order.Shares -= shares;
                    shares = 0;
                }
                else
                {
                    order.Subscription.Owned += order.Shares;
                    shares -= order.Shares;
                    order.Shares = 0;
                }

                order = order.Next;
            }

            index--;
        }

        if (shares > 0)
        {
            subscription.Owned -= originalShares - shares;

            var newOrder = new Order { Id = /*Interlocked.Increment(ref _orderId)*/_orderId++, Shares = shares, Subscription = subscription };

            // At this point Limits is guaranteed to have a single Limit.
            var prevLimit = Limits.ElementAt(index == Limits.Count - 1 ? index : ++index);
            if (prevLimit.Price == price)
            {
                newOrder.ParentLimit = prevLimit;
                if (prevLimit.AskHead == null)
                {
                    prevLimit.AskHead = newOrder;
                }
                else
                {
                    newOrder.Next = prevLimit.AskHead;
                    prevLimit.AskHead.Prev = newOrder;
                    prevLimit.AskHead = newOrder;
                }
            }
            else
            {
                var newLimit = new Limit { AskHead = newOrder, Price = price };
                newOrder.ParentLimit = newLimit;
                Limits.Add(newLimit);
            }

            Orders.Add(newOrder.Id, newOrder);
            return newOrder;
        }
        else
        {
            subscription.Owned -= originalShares;
        }

        return null;
    }
}
公共类订单簿
{
公共const int ScaleFactor=10_000;
私有长_orderId=1;
公共订购簿()
{
Limits=newrankedset(newlimitpricecomparer()){newlimit{Price=1*ScaleFactor};
订阅=新字典();
订单=新字典();
}
私有RankedSet限制{get;}
专用IDictionary订阅{get;}
私有IDictionary命令{get;}
公共秩序询问(长用户ID、长价格、整数共享)
{
如果(用户标识0)
{
if(order.Subscription.UserId==UserId)
{
if(order.Next==null)
{
打破
}
其他的
{
订单=订单。下一步;
}
}
//始终假设出价将有订阅,即使它是空的。
如果(order.Shares>=共享)
{
order.Subscription.Owned+=股份;
订单。股份-=股份;
股票=0;
}
其他的
{
order.Subscription.Owned+=order.Shares;
股份-=订单股份;
订单份额=0;
}
订单=订单。下一步;
}
索引--;
}
如果(共享>0)
{
认购。拥有-=原始股份-股份;
var newOrder=newOrder{Id=/*联锁。增量(ref _orderId)*/_orderId++,Shares=Shares,Subscription=Subscription};
//在这一点上,限制保证有一个单一的限制。
var prevLimit=Limits.ElementAt(index==Limits.Count-1?index:++index);
如果(prevLimit.Price==价格)
{
newOrder.ParentLimit=prevLimit;
if(prevLimit.AskHead==null)
{
prevLimit.AskHead=新订单;
}
其他的
{
newOrder.Next=prevLimit.AskHead;
prevLimit.AskHead.Prev=新订单;
prevLimit.AskHead=新订单;
}
}
其他的
{
var newLimit=新限额{AskHead=newOrder,Price=Price};
newOrder.ParentLimit=newLimit;
限制。添加(新限制);
}
Orders.Add(newOrder.Id,newOrder);
返回新订单;
}
其他的
{
认购。拥有-=原始股份;
}
返回null;
}
}
下面是我认为转换为聚合的一个开始。我遇到的问题是,当引发TradeExecutedEvent时,它需要整体修改聚合的状态。换句话说,如果该事件是自己触发的,那么它就没有意义,因为它依赖于它之前发生的事件。我认为需要TradeExecutedEvent的唯一原因是在UI上通知他们的交易已经执行

是否仍将TradeExecutedEvent存储在事件存储中,但不为其提供相应的Apply方法,以便通知其他服务/订阅者发生了交易

在我看来,我认为这是完全错误的,因为我认为聚合应该是短暂的,不会像这个一样长寿。如有任何建议或指导,我将不胜感激

public class TradeAggregate : AggregateBase
{
    private const int ScaleFactor = 10_000;
    private RankedSet<Limit> Limits { get; }
    private IDictionary<long, Subscription> Subscriptions { get; }
    private IDictionary<long, Order> Orders { get; }

    public TradeAggregate(string asset)
    {
        Limits = new RankedSet<Limit>(new LimitPriceComparer()) { new Limit { Price = 1 * ScaleFactor } };
        Subscriptions = new Dictionary<long, Subscription>();
        Orders = new Dictionary<long, Order>();
    }

    public void Ask(long userId, long price, int shares)
    {
        if (userId <= 0 || price <= 0 || shares <= 0)
        {
            // TODO: Return a message or something.
            return;
        }

        price = price * ScaleFactor;

        if (!Subscriptions.TryGetValue(userId, out Subscription subscription))
        {
            throw new System.Exception("You do not own this subscription.");
        }

        RaiseEvent(new AskOrderPlacedEvent(subscription, price, shares));
    }

    public void Apply(AskOrderPlacedEvent e)
    {
        var index = Limits.Count - 1;
        var shares = e.Shares;
        while (index >= 0 && shares > 0)
        {
            var currentLimit = Limits.ElementAt(index);
            if (currentLimit.Price < e.Price)
            {
                break;
            }

            Order order = currentLimit.BidHead;
            while (order != null && shares > 0)
            {
                if (order.Subscription.UserId == e.Subscription.UserId)
                {
                    if (order.Next == null)
                    {
                        break;
                    }
                    else
                    {
                        order = order.Next;
                    }
                }

                // Always assume the bid will have a subscription even if it's empty.
                if (order.Shares >= shares)
                {
                    RaiseEvent(new TradePartiallyExecutedEvent(order, shares, e.Subscription, e.Shares));
                    shares = 0;
                }
                else
                {
                    RaiseEvent(new TradeExecutedEvent(order, shares, e.Subscription, e.Shares));
                    shares -= order.Shares;
                }

                order = order.Next;
            }

            index--;
        }

        if (shares > 0)
        {
            // .... etc.
        }
        else
        {
            // .... etc.
        }
    }

    public void Apply(TradePartiallyExecutedEvent e)
    {
        e.Order.Subscription.Owned += e.Shares;
        e.Order.Shares -= e.Shares;
        e.Subscription.Owned -= e.OriginalShares - e.Shares;
    }

    public void Apply(TradeExecutedEvent e)
    {
        e.Order.Subscription.Owned += e.Order.Shares;
        e.Order.Shares = 0;
        e.Subscription.Owned -= e.OriginalShares;
    }
}
公共类TradeAggregate:AggregateBase
{
私有常量int ScaleFactor=10_000;
私有RankedSet限制{get;}
专用IDictionary订阅{get;}
私有IDictionary命令{get;}
公共交易汇总(字符串资产)
{
Limits=newrankedset(newlimitpricecomparer()){newlimit{Price=1*ScaleFactor};
订阅=新字典();
订单=新字典();
}
公共无效询问(长用户ID、长价格、整数共享)
{
如果(用户标识0)
{
if(order.Subscription.UserId==e.Subscription.UserId)
{
if(order.Next==null)
{
打破
}
其他的
{
订单=订单。下一步;
}
}
//始终假设出价将有订阅,即使它是空的。
如果(order.Shares>=共享)
{
RaiseEvent(新交易PartiallyExecutedEvent(订单、股份、认购、股份));
股票=0;
}
其他的
{
RaiseEvent(new TradeExecutedEvent(订单、股份、认购、股份));
股份-=订单股份;
}
订单=订单。下一步;
}
索引--;
}
如果(共享>0)
{
//……等等。
}
其他的
{
//……等等。
}
}
公共无效申请(交易部分执行事件e)
{
e、 Order.Subscription.Owned+=e.股份;
e、 订单.股份-=e.股份;
e、 认购。拥有-=e.原始股份-e.股份;
}
公开作废申请(TradeExecuted事件e)
{
e、 Order.Subscription.Owned+=e.Order.Shares;
e、 订单份额=0;
e、 Subscription.Owned-=e.Ori