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(-).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分支可以找到。
Asp.net Core 系列之--3.领域、仓储、服务简单实现的更多相关文章
- asp.net core 系列之webapi集成Dapper的简单操作教程
Dapper也是是一种ORM框架 这里记录下,使用ASP.NET 集成 Dapper 的过程,方便自己查看 至于Dapper的特性以及操作可以参考Dapper官方文档 1.创建数据库相关 在Sql S ...
- asp.net core 系列之webapi集成EFCore的简单操作教程
因为官网asp.net core webapi教程部分,给出的是使用内存中的数据即 UseInMemoryDatabase 的方式, 这里记录一下,使用SQL Server数据库的方式即 UseSql ...
- Asp.net Core 系列之--5.认证、授权与自定义权限的实现
ChuanGoing 2019-11-24 asp.net core系列已经来到了第五篇,通过之前的基础介绍,我们了解了事件订阅/发布的eventbus整个流程,初探dapper ORM实现,并且简单 ...
- Asp.net Core 系列之--2.ORM初探:Dapper实现MySql数据库各类操作
ChuanGoing 2019-09-10 距离上一篇近一个月时间,断断续续才把本篇码完,后面将加快进度,争取年度内把本系列基本介绍完成,同时督促本人持续学习. 本篇学习曲线: 1.初识Dapper ...
- Asp.net Core 系列之--4.事务、日志及错误处理
ChuanGoing 2019-11-17 这篇原本时想把事务处理.日志处理.错误处理.授权于鉴权一并介绍完的,授权和鉴权我想结合自定义权限来介绍,全部放到这里篇幅可能太长,因此权限部分将会在下篇来介 ...
- 【目录】asp.net core系列篇
随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...
- 1.1专题介绍「深入浅出ASP.NET Core系列」
大家好,我是IT人张飞洪,专注于.NET平台十年有余. 工作之余喜欢阅读和写作,学习的内容包括数据结构/算法.网络技术.Linux系统原理.数据库技术原理,设计模式.前沿架构.微服务.容器技术等等…… ...
- asp.net core系列 30 EF管理数据库架构--必备知识 迁移
一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...
- asp.net core系列 40 Web 应用MVC 介绍与详细示例
一. MVC介绍 MVC架构模式有助于实现关注点分离.视图和控制器均依赖于模型. 但是,模型既不依赖于视图,也不依赖于控制器. 这是分离的一个关键优势. 这种分离允许模型独立于可视化展示进行构建和测试 ...
随机推荐
- ES6 —— entries(),keys()和values()
ES6 提供三个新的方法 —— entries(),keys()和values() —— 用于遍历数组.它们都返回一个遍历器对象,可以用for...of循环进行遍历,唯一的区别是keys()是对键名的 ...
- vodevs3031 最富有的人
在你的面前有n堆金子,你只能取走其中的两堆,且总价值为这两堆金子的xor值,你想成为最富有的人,你就要有所选择. 输入描述 Input Description 第一行包含两个正整数n,表示有n堆金子. ...
- 安装高可用Hadoop生态 (三) 安装Hadoop
3. 安装Hadoop 3.1. 解压程序 ※ 3台服务器分别执行 .tar.gz -C/opt/cloud/packages /opt/cloud/bin/hadoop /etc/hadoop ...
- C# 获取pdf长宽,反推pdf图纸类型
业务需求:读取pdf每页的长宽,然后根据国际标准,反推出pdf图纸类型 第一步:下载类库,并引入到项目中 链接:https://pan.baidu.com/s/1ud4-xhfDvi9OKolEBPw ...
- 0基础学Java快速扫盲指南,月入2W的基础
学Java,掌握一些基本的概念是第一步,本文简单为大家介绍一些扫盲级别的内容,希望帮助小白快速入门. 一.基本概念 JVM:java虚拟机,负责将编译产生的字节码转换为特定机器代码,实现一次编译多处执 ...
- 基于Spark的电影推荐系统(推荐系统~2)
第四部分-推荐系统-数据ETL 本模块完成数据清洗,并将清洗后的数据load到Hive数据表里面去 前置准备: spark +hive vim $SPARK_HOME/conf/hive-site.x ...
- top命令之性能分析
top命令详解 当前时间20:27:12 当前系统运行时间3:18秒 1个用户 系统负载平均长度为0.00,0.00,0.00(分别为1分钟.5分钟.15分钟前到现在的平均值) 第二行为进程 ...
- 在博客中增加自己的live2d纸片人模型方法
目录 在博客中增加自己的live2d纸片人模型 准备工具 使用步骤 附件 在博客中增加自己的live2d纸片人模型 准备工具 github仓库:存放live2d模型和json文件 如果你的博客支持本地 ...
- Mysql数据类型最细讲解
文章原创于公众号:程序猿周先森.本平台不定时更新,喜欢我的文章,欢迎关注我的微信公众号. 数据库中事务是最重要的概念之一,所以上篇着重谈了谈数据库中事务的使用,并且举了实例如何在实际开发中去使用事务进 ...
- 【websocket】spring boot 集成 websocket 的四种方式
集成 websocket 的四种方案 1. 原生注解 pom.xml <dependency> <groupId>org.springframework.boot</gr ...