• Asp.net Core 系列之--3.领域、仓储、服务简单实现


    ChuanGoing 2019-11-11 

       距离上篇近两个月时间,一方面时因为其他事情耽搁,另一方面也是之前准备不足,关于领域驱动有几个地方没有想通透,也就没有继续码字。目前网络包括园子里大多领域驱动设计的文章,关于仓储者一层都没有详细的说明,只是简单的一笔带过:领域驱动不关心具体的持久化如何落地。但是,作为"猿人类"就不可避免的绕不开持久化。本篇将会简略的介绍利用Dapper这个轻量级的ORM来实现如何持久化。

    本篇学习曲线:

    1.领域模型

    2.领域仓储

    3.简单服务实现

    领域模型设计

      我这里用常见的电商业务模型来介绍领域模型的设计,因篇幅有限,这里主要介绍订单与订单明细模型,基于如下业务:

    1.创建订单时生成订单号、计算商品的总价同时生成订单明细。

    2.根据订单号获取订单信息

      我的这个例子基本上涵盖了领域模型的主要几种业务组合:领域-实体-值对象,这几个基本概念这里不做赘述,园子里一搜一大堆。

    public partial class Order : DomainEntity<Guid>
        {
            /// <summary>
            /// 订单流水号
            /// </summary>
            public string Sn { get; private set; }
            /// <summary>
            /// 总价
            /// </summary>
            public decimal TotalPrice { get; private set; }
            /// <summary>
            /// 状态
            /// </summary>
            public OrderStatus Status { get; private set; }
            /// <summary>
            /// 支付时间
            /// </summary>
            public long PaymentTime { get; private set; }
            /// <summary>
            /// 过期时间
            /// </summary>
            public long ExpireTime { get; private set; }
            /// <summary>
            /// 备注
            /// </summary>
            public string Description { get; private set; }
            /// <summary>
            /// 用户
            /// </summary>
            public Guid UserId { get; private set; }
    
            public string Adress { get; private set; }
    
            /// <summary>
            /// 订单明细
            /// </summary>
            [Ignore]
            public List<OrderItem> OrderItems { get; private set; }
        }
    订单
     public partial class OrderItem : Entity<Guid>
        {
            /// <summary>
            /// 订单编号
            /// </summary>
            public Guid OrderId { get; private set; }
            /// <summary>
            /// 商品编号
            /// </summary>
            public Guid ProductId { get; private set; }
            /// <summary>
            /// 商品单价
            /// </summary>
            public decimal Price { get; private set; }
            /// <summary>
            /// 数量
            /// </summary>
            public int Count { get; private set; }
            /// <summary>
            /// 加入时间
            /// </summary>
            public long JoinTime { get; private set; }
        }
    订单详情

    可以看到Order类为DomainEntity(领域实体-聚合根),OrderItem为Entity(实体),Order和OrderItem组成一个业务聚合。为什么这么划分呢?有两方面的原因:

    1.本例不涉及复杂业务,没有直接针对订单明细的业务操作

    2.订单明细依赖于订单,生命周期随着订单主体产生和消逝

     订单和订单明细都被设计为"partial",因为到目前为止,我们的实体类还是POCO,也就是通常所说的贫血模型。因此,为了赋予模型活力,我们需要为其添加某些行为:

    public partial class Order
        {
            public void Add(Guid userId, Adress adress, string description, List<OrderItem> orderItems)
            {
                Sn = Guid.NewGuid().ToString("N");
                TotalPrice = orderItems.Sum(i => i.Price * i.Count);
                Status = OrderStatus.TobePaid;
                ExpireTime = DateTimeOffset.Now.AddMinutes(-30).ToUnixTimeMilliseconds();
                UserId = userId;
                Adress = adress.ToString();
                Description = description;
                orderItems.ForEach(i =>
                {
                    i.SetOrder(this);
                });
                SetItems(orderItems);
            }
    
            public void Pay()
            {
                Status = OrderStatus.Paid;
                PaymentTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
            }
    
            public void SetItems(List<OrderItem> orderItems)
            {
                OrderItems = orderItems;
            }
        }
    订单行为

    这样,我们给领域赋予了某些行为。

    领域仓储

    结合我上篇Asp.net Core 系列之--2.ORM初探:Dapper实现MySql数据库各类操作介绍的仓储示例,这里为领域模型单独设计了"领域仓储层"

    public class OrderRepository : DapperRepository<Order, Guid>, IOrderRepository
        {
            public OrderRepository(IComponentContext container, IDapperDbContext dbContext)
                : base(container, dbContext)
            {
    
            }
    
            public Order GetBySn(string sn)
            {
                var order = QuerySingleOrDefault<Order>("SELECT * FROM `Order` WHERE `Sn`=@Sn;", new
                {
                    Sn = sn
                });
                if (order != null)
                {
                    order.SetItems(Query<OrderItem>("SELECT * FROM `OrderItem` WHERE `OrderId`=@OrderId;", new
                    {
                        OrderId = order.Id
                    }).ToList());
                }
                return order;
            }
        }
    领域仓储

    领域仓储实现了Domain中定义的接口

     public interface IOrderRepository : IRepository<Order, Guid>, IScopeInstance
        {
            Order GetBySn(string sn);
        }
    订单仓储接口定义

    值得注意的时,领域仓储层这里起到了承上启下的作用,隔离了领域对于持久化层的直接依赖。

    简单服务实现

        接下来,我们实现如何在业务服务层调用领域仓储实现数据的持久化。新建Application项目:

     定义订单接口服务

    public interface IOrderService : IScopeInstance
        {
            void Add(OrderViewModel order);
            OrderViewResult Get(string sn);
        }

    订单服务实现

     public void Add(OrderViewModel view)
            {
                if (view == null) new Exception("参数无效");
                var order = new Order();
                Mapper.Map(view, order);
    
                order.Add(view.UserId, view.Adress, view.Description, order.OrderItems);
                _repo.Insert(order);
                order.OrderItems.ForEach(i => _itemRepo.Insert(i));
            }
    
            public OrderViewResult Get(string sn)
            {
                var order = _repo.GetBySn(sn);
    
                OrderViewResult result = new OrderViewResult();
                return order == null ? null : Mapper.Map(order, result);
            }

    在Webapi项目控制器文件夹下新建OrderController

    public class OrderController : Controller
        {
            private readonly IOrderService _service;
    
            public OrderController(IOrderService service)
            {
                _service = service;
            }
    
            [HttpPost]
            public void Add([FromBody]OrderViewModel order)
            {
                _service.Add(order);
            }
    
            [HttpGet]
            public OrderViewResult Get([FromQuery]string sn)
            {
                return _service.Get(sn);
            }
        }

    具体代码请看篇末源代码链接

    这样,我们实现了领域模型的持久化。

    看下效果,用postman测试下创建和获取订单信息

    订单参数如上

     

    调试信息-订单创建

     

    根据订单编号,返回订单信息

    回顾

      回顾一下本篇内容,分别介绍了:领域模型、领域仓储、简单服务的实现,然后利用postman模拟http请求演示了数据的创建与获取。

      本篇只是简单的介绍了领域服务及相关概念,后面有机会再做详细讨论,下篇将介绍日志、鉴权、错误及事物处理。

    代码

      本篇涉及的源码在Github的https://github.com/ChuanGoing/Start.git  的Domain分支可以找到。

  • 相关阅读:
    python2
    python1
    jmeter基础使用
    LoadRuuner资源监控
    UI自动化
    MYSQL增删改查添加外键
    DW网页代码笔记
    Linux常用命令(常用)
    Linux常用命令大全(全全全!!!)
    第十二章 : shell 环境
  • 原文地址:https://www.cnblogs.com/ChuanGoing/p/11624228.html
Copyright © 2020-2023  润新知