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数据库各类操作的更多相关文章

  1. Asp.net Core 系列之--1.事件驱动初探:简单事件总线实现(SimpleEventBus)

    ChuanGoing 2019-08-06  前言 开篇之前,简单说明下随笔原因.在园子里游荡了好久,期间也起过要写一些关于.NET的随笔,因各种原因未能付诸实现. 前段时间拜读daxnet的系列文章 ...

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

    ChuanGoing 2019-11-11  距离上篇近两个月时间,一方面时因为其他事情耽搁,另一方面也是之前准备不足,关于领域驱动有几个地方没有想通透,也就没有继续码字.目前网络包括园子里大多领域驱 ...

  3. Asp.net Core 系列之--4.事务、日志及错误处理

    ChuanGoing 2019-11-17 这篇原本时想把事务处理.日志处理.错误处理.授权于鉴权一并介绍完的,授权和鉴权我想结合自定义权限来介绍,全部放到这里篇幅可能太长,因此权限部分将会在下篇来介 ...

  4. 【目录】asp.net core系列篇

    随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...

  5. asp.net core系列 36 WebAPI 搭建详细示例

    一.概述 HTTP不仅仅用于提供网页.HTTP也是构建公开服务和数据的API强大平台.HTTP简单灵活且无处不在.几乎任何你能想到的平台都有一个HTTP库,因此HTTP服务可以覆盖广泛的客户端,包括浏 ...

  6. Asp.net Core 系列之--5.认证、授权与自定义权限的实现

    ChuanGoing 2019-11-24 asp.net core系列已经来到了第五篇,通过之前的基础介绍,我们了解了事件订阅/发布的eventbus整个流程,初探dapper ORM实现,并且简单 ...

  7. 1.1专题介绍「深入浅出ASP.NET Core系列」

    大家好,我是IT人张飞洪,专注于.NET平台十年有余. 工作之余喜欢阅读和写作,学习的内容包括数据结构/算法.网络技术.Linux系统原理.数据库技术原理,设计模式.前沿架构.微服务.容器技术等等…… ...

  8. asp.net core系列 30 EF管理数据库架构--必备知识 迁移

    一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...

  9. asp.net core系列 40 Web 应用MVC 介绍与详细示例

    一. MVC介绍 MVC架构模式有助于实现关注点分离.视图和控制器均依赖于模型. 但是,模型既不依赖于视图,也不依赖于控制器. 这是分离的一个关键优势. 这种分离允许模型独立于可视化展示进行构建和测试 ...

随机推荐

  1. 01 python安装与初识

    一.简要概述 python学习时设计要大于开发. 二.编程语言 1.分类 编程语言分为高级语言和低级语言.高级语言如python.c#,Java.PHP等,低级语言(基础语言)如C.汇编语言. 2.机 ...

  2. C#通过对象属性名修改值

    摘自:csdn 给一个对象属性赋值可以通过PropertyInfo.SetValue()方式进行赋值,但要注意值的类型要与属性保持一致.    创建对象实例的两种方法: 1. var obj = As ...

  3. SQL SERVER数据库,按年、月、日、时、分、秒计算两个时间字段之间的间隔时间样例

    使用DATEDIFF(取值,时间字段1,时间字段2) 举例: SELECT DATEDIFF(YEAR,DRYSJ,DCYSJ),* FROM YXHIS2019..TBZYBR2019 --SQL ...

  4. Python调用GithubAPI并进行初步的数据分析

    找到一个Github 上的公开api url = 'https://api.github.com/search/repositories?q=language:python&sort=star ...

  5. 算法学习之剑指offer(八)

    题目一 题目描述 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100.但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数).没 ...

  6. Cocos2d-x 学习笔记(11.3) JumpBy JumpTo

    1. JumpBy JumpTo JumpBy,边跳边平移,不只做垂直向上的抛物动作,同时还在向终点平移.JumpTo是JumpBy的子类. 1.1 成员变量 create方法 JumpBy: Vec ...

  7. linux下 Mysql 安装使用

    .安装mysql sudo apt-get install mysql-server mysql-client sudo service mysql restart 2.5.7版本以上修修改updat ...

  8. C# Halcon混合编程中遇到的问题(一)

    目标平台 安装64位的halcon的情况下,目标平台必须使用x64而不能使用x86 目标框架 不能使用.Net Framework Client版本,有一些必须的程序集会缺失,测试使用.Net Fra ...

  9. xml 文件操作

      'XML添加   Public Sub Add(ID As String, RFSerialnumber As String, Mood As Integer)     If reatch(RFS ...

  10. vue入门笔记(新手入门必看)

    一.什么是Vue? 1.    vue为我们提供了构建用户界面的渐进式框架,让我们不再去操作dom元素,直接对数据进行操作,让程序员不再浪费时间和精力在操作dom元素上,解放了双手,程序员只需要关心业 ...