领域驱动设计实战案例(七):订单上下文应用服务用例与接口

zhuiqiuuuu 2019-06-27

DDD实战进阶第一波:开发一般业务的大健康行业直销系统

上一篇文章我们主要讲了订单上下文的领域逻辑,在领域逻辑中完成了订单项的计算逻辑、订单的计算逻辑以及如何生成相应的实体code,这篇文章我们通过在应用服务中实现一个下单的用例,来将这些领域逻辑以及仓储整合起来,完成一个下单的用例。

先看下单用例主体的代码:

public class CreateOrderUseCase:BaseAppSrv

{
    private readonly IOrderRepository iorderrepository;
    private readonly IDealerRepository idealerrepository;
    private readonly IRepository[] irepositories;
    

    public CreateOrderUseCase(IOrderRepository iorderrepository,IDealerRepository idealerrepository,
        params IRepository[] irepositories)
    {
        this.iorderrepository = iorderrepository;
        this.idealerrepository = idealerrepository;
        this.irepositories = irepositories;
    }
    public ResultEntity<bool> CreateOrder(OrderDTO orderdto)
    {
        var orderid = Guid.NewGuid();
        Orders order = new Orders();
        var productskus = new List<ProductSKU>();
        for(int i = 0; i < orderdto.ProductSPUNames.Count; i++)
        {
            var productsku = new ProductSKU();
            productsku.ProductSPUName = orderdto.ProductSPUNames[i];
            productsku.DealerPrice = orderdto.ProductDealerPrices[i];
            productsku.PV = orderdto.ProductPVS[i];
            productsku.Id = orderdto.ProductSKUIds[i];
            productsku.Spec = orderdto.ProductSepcs[i];
            productskus.Add(productsku);
        }
        var contact = new Contact();
        contact.ContactName = orderdto.ContactName;
        contact.ContactTel = orderdto.ContactTel;
        contact.Province = orderdto.Privence;
        contact.City = orderdto.City;
        contact.Zero = orderdto.Zero;
        contact.Street = orderdto.Street;

        var orders = order.CreateOrders(orderid, orderdto.DealerId, productskus, orderdto.Counts,
            contact);

        try
        {
            //using (var tansaction = new TransactionScope())
            //{
                using (irepositories[1])
                {
                    idealerrepository.SubParentEleMoney(orderdto.DealerId, order.OrderTotalPrice.TotalPrice);
                    idealerrepository.AddDealerPV(orderdto.DealerId, order.OrderTotalPV.TotalPV);
                    irepositories[1].Commit();

                }

                using (irepositories[0])
                {
                    iorderrepository.CreateOrder(orders);
                    irepositories[0].Commit();
                }
            return GetResultEntity(true);
                //tansaction.Complete();
            //}
        }
        catch(EleMoneyNotEnoughException error)
        {
            throw error;
        }
        catch(Exception error)
        {
            throw error;
        }
        
    }
}

IOrderRepository仓储接口主要完成订单的预持久化工作,我们来看下它的实现:

public class OrderEFCoreRepository : IOrderRepository

{
    private readonly DbContext context;
        
    public OrderEFCoreRepository(DbContext context)
    {
        this.context = context;
    }
    public void CreateOrder<T>(T order) where T:class,IAggregationRoot
    {
        var ordercontext = this.context as OrderEFCoreContext;
        var ordernew = order as Orders;
        try
        {
            ordercontext.Order.Add(ordernew);
        }
        catch(Exception error)
        {
            throw error;
        }
    }

}

IDealerRepository仓储接口主要用来下单完成后,扣减对应经销商的电子币与累加PV,相关方法实现代码如下:

public void SubParentEleMoney(Guid parentdealerid, decimal subelemoney)

{
        var dealercontext = this.context as DealerEFCoreContext;
        var parentdealer = dealercontext.Dealer.Single(p => p.Id == parentdealerid);
        parentdealer.TotalEleMoney = parentdealer.TotalEleMoney - subelemoney;
        if (parentdealer.TotalEleMoney < 0)
        {
            throw new EleMoneyNotEnoughException("电子币不够进行此操作!");
        }
        try
        {
            dealercontext.Entry(parentdealer).State = EntityState.Modified;
        }
        catch(Exception error)
        {
            throw error;
        }
    }

    public void AddDealerPV(Guid dealerid, decimal orderpv)
    {
        var dealercontext = this.context as DealerEFCoreContext;
        var dealer = dealercontext.Dealer.Single(p => p.Id == dealerid);
        dealer.TotalPV = dealer.TotalPV +orderpv;
        try
        {
            dealercontext.Entry(dealer).State = EntityState.Modified;
        }
        catch (Exception error)
        {
            throw error;
        }
    }

IRepository[]用于订单与经销商两个的数据访问仓储,完成真正的持久化,在第一部分主体代码中注释掉的using (var tansaction = new TransactionScope())与
tansaction.Complete();是因为在.net core 2.0版本中,不支持多个数据访问上下文的事务,在.net core 2.1版本中可以使用,这样就完成了订单数据与经销商数据的事务一致性。

最后我们通过webapi完成对应用服务的调用,实现代码如下

[HttpPost]

[Route("CreateOrder")]
    public ResultEntity<bool> CreateOrder([FromBody] OrderDTO orderdto)
    {
        var result = new ResultEntity<bool>();
        var ordercontext = new OrderEFCoreContext();
        var dealercontext = new DealerEFCoreContext();
        var irepository = new EFCoreRepository(ordercontext);
        var irepository1 = new EFCoreRepository(dealercontext);
        var iorderrepository = new OrderEFCoreRepository(ordercontext);
        var idealerrepository = new DealerEFCoreRepository(dealercontext);
        var createorderusecase = new CreateOrderUseCase(iorderrepository, idealerrepository,
            irepository, irepository1);
        try
        {
            result = createorderusecase.CreateOrder(orderdto);
            result.Count = 1;
            result.IsSuccess = true;
            result.Msg = "下单成功!";
        }
        catch (EleMoneyNotEnoughException error)
        {
            result.ErrorCode = 300;
            result.Msg = error.Message;
        }
        catch (Exception error)
        {
            result.ErrorCode = 200;
            result.Msg = error.Message;
        }
        return result;
    }

因为这里只是做演示,具体接口与实现没有通过依赖注入框架注入,这部分内容可以自己去实现。

QQ讨论群:309287205
DDD实战进阶视频请关注微信公众号:msshcj

相关推荐