Asp.net Core 系列之--2.ORM初探:Dapper实现MySql数据库各类操作
ChuanGoing 2019-09-10
距离上一篇近一个月时间,断断续续才把本篇码完,后面将加快进度,争取年度内把本系列基本介绍完成,同时督促本人持续学习。
本篇学习曲线:
1.初识Dapper
2.DbConnection
3.CommandBuilder实现单表操作(略)
4.演示
初识Dapper
Dapper是一个轻量级/高性能的ORM,核心功能是利用Emit反射获取IDataReader中的数据。我们可以利用它的对象关系映射实现简单CURD操作,或者直接用SQL语句实现复杂场景的CURD操作。
DbConnection
顾名思义,数据库连接对象。Dapper提供DbConnection对象的扩展来操作数据库
public virtual int Execute(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null)
{
return _dbConnection.Execute(sql: sql, param: param, transaction: null, commandTimeout: commandTimeout, commandType: commandType);
} public virtual IEnumerable<TResult> Query<TResult>(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null)
{
return _dbConnection.Query<TResult>(sql: sql, param: param, transaction: null, commandTimeout: commandTimeout, commandType: commandType);
}
上面贴出的两个方法:Execute方法执行(增删改),Query执行查询操作。由此可以看到,Dapper操作数据库主要是手写SQL,当然我们也可以封装一些常用的方法来提高开发效率。
当然,本篇重点不在于Dapper的介绍。接下来看看如何对Dapper来封装出我们自己可用的ORM。
CommandBuilder实现单表操作需要实现通用的单表的增删改查,我们得先定义/分解SQL语句:
1.操作的表对象(表)
2.表对象中的列对象(字段)
3.条件
定义字段对象/对象集合
public class Field
{
public Field(string name, object value = null)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException(nameof(name), "invalid name");
}
Name = name;
Value = value;
}
public string Name { set; get; }
public object Value { set; get; }
}
public class FieldsCollection : IEnumerable<Field>
{
private List<Field> _fields;
public Field this[int index] => _fields[index]; public FieldsCollection()
{
_fields = new List<Field>();
} public int Count => _fields.Count; public void Add(Field field)
{
_fields.Add(field);
} public void Add(params Field[] fields)
{
_fields.AddRange(fields);
} public IEnumerable<Field> GetFields()
{
return _fields;
} public IEnumerator<Field> GetEnumerator()
{
return _fields.GetEnumerator();
} IEnumerator IEnumerable.GetEnumerator()
{
return _fields.GetEnumerator();
}
}
定义条件
public abstract class Filter
{
public Filter(string field)
{
Field = field;
}
public virtual string Field { get; private set; }
}
/// <summary>
/// 相等过滤
/// </summary>
public class EqualFilter : Filter
{
public EqualFilter(string field, object value)
: base(field)
{
Value = value;
}
public object Value { get; }
}
这里只贴出了"相等"条件,详细代码请查看篇尾给出的Github源码链接
定义排序字段
public class Sort
{
public string Field { get; set; }
public bool Order { get; set; } public Sort(string field, bool order = true)
{
Field = field;
Order = order;
}
}
查询语句的组装
public class QueryParameter
{
private List<Filter> _filters;
private List<Sort> _sorts;
public QueryParameter(FieldsCollection fileds, IEnumerable<Filter> filters = null, IEnumerable<Sort> sorts = null)
{
Fields = fileds.GetFields();
_filters = new List<Filter>();
if (filters != null)
{
_filters.AddRange(filters);
}
_sorts = new List<Sort>();
if (sorts != null)
{
_sorts.AddRange(sorts);
}
} public void AddFilter(Filter filter)
{
_filters.Add(filter);
} public void AddSort(Sort sort)
{
_sorts.Add(sort);
} public IEnumerable<Field> Fields { get; }
public IEnumerable<Filter> Filters => _filters;
public IEnumerable<Sort> Sorts => _sorts;
}
完成以上对象定义后,我们再来看看如何利用上述对象完成增删改查操作
public SqlCommand GetCommand(TPrimaryKey key)
{
var obj = GetObjectContext<TEntity>();
FieldsCollection fields = new FieldsCollection();
List<Filter> filters = new List<Filter>();
foreach (var prop in obj.Properties)
{
foreach (var attr in prop.Attributes)
{
if (attr is PrimaryKeyAttribute keyAttr)
{
filters.Add(new Equal(prop.Info.Name, key));
}
} fields.Add(new Field(prop.Info.Name));
} QueryParameter queryParameter = new QueryParameter(fields, filters);
return CommandBuilder.QueryCommand(obj.Table, queryParameter, count: );
}
查询方法是根据主键做查询操作,其中数据库上下文对象通过泛型对象反射得到
public virtual ObjectContext GetObjectContext<T>()
{
var type = typeof(T); string tableKey = ObjectContext.GetTableKey(typeof(T)); return DbContext.ObjectCollection.GetOrAdd(tableKey, entity => new ObjectContext(type));
}
新增方法类似上面的查询,只是SQL语句形式有区别
public SqlCommand InsertCommand(TEntity entity)
{
var obj = GetObjectContext<TEntity>();
FieldsCollection fields = new FieldsCollection();
foreach (var prop in obj.Properties)
{
fields.Add(new Field(prop.Info.Name, prop.Info.GetValue(entity)));
}
var com = CommandBuilder.InsertCommand(obj.Table, fields);
return com;
}
查询/新增方法,可以看到,上面代码通过反射/缓存得到增删改查的参数/值得信息,到这里为止,还没有形成有效的SQL语句。那么如何实现呢?
由于各个数据库(Mysql/Mssql/oracle..)中SQL语法有些差异,因此转化SQL的工作应该交由具体的某种数据库语句生成器去生成。本例采用的是Mysql数据库,因此我们可以看到上诉代码中涉及到CommandBuilder是基于mysql实现的,具体代码在这里就不贴了,详情看篇末Github链接。
演示
基于上一篇Asp.net Core 系列之--1.事件驱动初探:简单事件总线实现(SimpleEventBus),改写一下CustomersController,repository由直接通过sql语句操作替换为本篇实现的封装代码,然后将事件/事件处理定义、实体/Dto等移到Domain层(为后续介绍铺路)
private readonly IRepository<Customer, Guid> _repository;
private readonly IEventBus _eventBus; public CustomersController(IEventBus eventBus, IRepository<Customer, Guid> repository)
{
_repository = repository;
_eventBus = eventBus;
} // 获取指定ID的客户信息
[HttpGet("{id}")]
public async Task<IActionResult> Get(Guid id)
{
var customer = await _repository.GetAsync(id); if (customer == null)
{
return NotFound();
}
return Ok(customer);
} // 创建新的客户信息
[HttpPost]
public async Task<IActionResult> Create([FromBody] CustomerDto model)
{
var name = model.Name;
if (string.IsNullOrEmpty(name))
{
return BadRequest();
} var customer = new Customer(name);
var result = await _repository.InsertAsync(customer);
await _eventBus.PublishAsync(new CustomerCreatedEvent(name)); return Created(Url.Action("Get", new { id = customer.Id }), customer.Id);
}
运行程序后,正确得到返回数据
Dapper实现ORM基本功能到此算告一段落,读者有兴趣的话可以查阅Dapper源码,后续有机会的话再介绍下它的扩展功能
回顾
回顾一下本篇内容,首先简单介绍了Dapper是什么、能做什么,然后我们基于mysql实现了Dapper的简单对象关系映射,最后利用WinPowershell的Invoke-WebRequest模拟http请求演示了数据的创建与获取。
本篇已涉及到仓储的概念,也是领域模型的重要环节,后续我们将会渐进式的介绍DDD相关概念及设计原理
代码
本篇涉及的源码在Github的https://github.com/ChuanGoing/Start.git 的DapperOrm分支可以找到。
Asp.net Core 系列之--2.ORM初探:Dapper实现MySql数据库各类操作的更多相关文章
- Asp.net Core 系列之--1.事件驱动初探:简单事件总线实现(SimpleEventBus)
ChuanGoing 2019-08-06 前言 开篇之前,简单说明下随笔原因.在园子里游荡了好久,期间也起过要写一些关于.NET的随笔,因各种原因未能付诸实现. 前段时间拜读daxnet的系列文章 ...
- Asp.net Core 系列之--3.领域、仓储、服务简单实现
ChuanGoing 2019-11-11 距离上篇近两个月时间,一方面时因为其他事情耽搁,另一方面也是之前准备不足,关于领域驱动有几个地方没有想通透,也就没有继续码字.目前网络包括园子里大多领域驱 ...
- 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 ...
- asp.net core系列 36 WebAPI 搭建详细示例
一.概述 HTTP不仅仅用于提供网页.HTTP也是构建公开服务和数据的API强大平台.HTTP简单灵活且无处不在.几乎任何你能想到的平台都有一个HTTP库,因此HTTP服务可以覆盖广泛的客户端,包括浏 ...
- Asp.net Core 系列之--5.认证、授权与自定义权限的实现
ChuanGoing 2019-11-24 asp.net core系列已经来到了第五篇,通过之前的基础介绍,我们了解了事件订阅/发布的eventbus整个流程,初探dapper ORM实现,并且简单 ...
- 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架构模式有助于实现关注点分离.视图和控制器均依赖于模型. 但是,模型既不依赖于视图,也不依赖于控制器. 这是分离的一个关键优势. 这种分离允许模型独立于可视化展示进行构建和测试 ...
随机推荐
- Java面试----01.JavaSE
1.面向对象和面向过程的区别 面向过程:面向过程性能比面向对象高. 因为类调用时需要实例化,比较消耗资源,所以当性能是最重要的考虑因素时,比如单片机.嵌入式开发.Linux/Unix等一般采用面向对象 ...
- TinyXML2的快速实践
最近遇到个需要在C++中处理XML文件的需求,虽然对此方面并不是很熟,但好在有GitHub上的awesome-cpp项目的帮助,还是收获了足够的相关知识. 类库 常用的或被推荐的XML类库有以下数个选 ...
- 【Tomcat】tomcat7 设置成系统服务启动
1.启动cmd 2.cd C:\Program Files\tomcat7\bin 3.service.bat install 4.打开tomcat7w.exe可以启动管理服务
- .NET进阶篇-语言章-2-Delegate委托、Event事件
知识只有经过整理才能形成技能 整个章节分布简介请查看第一篇 内容目录 一.概述 二.解析委托知识点 1.委托本质 2.委托的使用 3.委托意义 逻辑解耦,减少重复代码 代码封装支持扩展 匿名方法和La ...
- Kafka技术原理知识点总结
1.Kafka是由Linkedin公司开发的,使用Scala语言编写的,分布式,多副本,多分区的,发布订阅模式的消息系统,他通常用于日志系统的搭建,2.Kafka和Zookeeper:Kafka通过Z ...
- 分库分表(7)--- SpringBoot+ShardingSphere实现分库分表 + 读写分离
分库分表(7)--- ShardingSphere实现分库分表+读写分离 有关分库分表前面写了六篇博客: 1.分库分表(1) --- 理论 2.分库分表(2) --- ShardingSphere(理 ...
- python程序编译成exe文件
最近越来越喜欢使用python写工具.使用的时候,发现程序内部成员python安装目录常常不同,如果用bat双击执行,常常需要修改从svn上down下来的bat文件中python.exe的路径.而给策 ...
- Podman 使用指南
原文链接:Podman 使用指南 Podman 原来是 CRI-O 项目的一部分,后来被分离成一个单独的项目叫 libpod.Podman 的使用体验和 Docker 类似,不同的是 Podman 没 ...
- java中的静态
static静态 public static void main 类只是用来存储和被调用的,而对象是需要执行的,执行时就必定需要知道程序的入口,这个入口就是由main所在的位置. Java的类中没有m ...
- Windows API 编程入门
Windows 工作原理的中心思想就是“动态链接”概念.Windows 自身带有一大套函数,应用程序就是通过调用这些函数 来实现它的用户界面和在屏幕上显示文本和图形的.这些函数都是在动态链接库里实现的 ...