前几天偶然看到了dapper,由于以前没有用过,只用过ef core,稍微看了一下,然后写了一些简单的可复用的封装。

Dapper的用法比较接近ADO.NET所以性能也是比较快。所以我们先来看看使用ADO.NET的时候我们怎么实现代码复用的封装。

一、ADO.NET的封装案例

利用反射对ADO.NET进行封装,看代码:

DBHelper.cs:这边用的是mysql,如果要用sqlserver将MySqlConnection换成SqlConnection即可。

这个写的比较简单,如果有复杂的sql可能就支持不了了。读取配置文件的代码需要用到两个包:

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
using MySqlConnector;
namespace DB.Model

{

public class DBHelper

{

private static IConfiguration Configuration { get; set; }

private static readonly string ConnStr = null;

private static MySqlConnection conn;

static DBHelper()

{

//ReloadOnChange = true 当appsettings.json被修改时重新加载

Configuration = new ConfigurationBuilder()

.Add(new JsonConfigurationSource { Path = "appsettings.json", ReloadOnChange = true }).Build();

ConnStr = Configuration.GetConnectionString("MySql");

}

public static void Init()

{

if (connnull)

{

conn = new MySqlConnection(ConnStr);

conn.Open();

}

else if (conn.State ConnectionState.Closed)

{

conn.Open();

}

else if(conn.State==ConnectionState.Broken)

{

conn.Close();

conn.Open();

}

}

/// <summary>

/// 查全部

/// </summary>

/// <typeparam name="T"></typeparam>

/// <returns></returns>

public static List<T> GetDataAll<T>()

{

Init();

Type type = typeof(T);

//用type.Name代替表名

string sql = $"select * from {type.Name}";

MySqlCommand cmd = new MySqlCommand(sql, conn);

List<T> Data = new List<T>();

MySqlDataReader reader= cmd.ExecuteReader();

while (reader.Read())

{

object obj = Activator.CreateInstance(type);

foreach (PropertyInfo property in type.GetProperties())

{

property.SetValue(obj,reader[property.Name]);

}

Data.Add((T)obj);

}

reader.Close();

conn.Close();

return Data;

}

/// <summary>

/// 按id查询

/// </summary>

/// <typeparam name="T"></typeparam>

/// <param name="id"></param>

/// <returns></returns>

public static T GetDataById<T>(int id)

{

Init();

Type type = typeof(T);

string sql = $"select * from {type.Name} where id={id}";

MySqlCommand cmd = new MySqlCommand(sql, conn);

MySqlDataReader reader = cmd.ExecuteReader();

object obj = Activator.CreateInstance(type);

while (reader.Read())

{

foreach (PropertyInfo property in type.GetProperties())

{

property.SetValue(obj,reader[property.Name]);

}

}

reader.Close();

conn.Close();

return (T) obj;

}

/// <summary>

/// 单条添加数据

/// </summary>

/// <typeparam name="T"></typeparam>

/// <param name="t"></param>

/// <returns></returns>

public static int Add<T>(T t)

{

Init();

Type type = t.GetType();

Func<PropertyInfo, object> f = (x) =>

{

if (x.GetValue(t).GetType().Equals(typeof(string)))

{

return $"'{x.GetValue(t)}'";

}

else

{

return x.GetValue(t);

}

};

string sql = $"insert into {type.Name} " +

$"({string.Join(",", type.GetProperties().Select(n => $"{n.Name}"))}) " +

$"values({string.Join(",", type.GetProperties().Select(n => $"{f(n)}"))})";

MySqlCommand cmd = new MySqlCommand(sql,conn);

int result = cmd.ExecuteNonQuery();

conn.Close();

return result;

}

}

}

二、Dapper原生封装

dapper框架是给IDBConnection写了一些扩展方法,底层还是反射实现对象的关系映射。我们使用的时候只需要会用泛型即可。

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Dapper;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json; namespace Model

{

public class DapperHelper

{

static DapperHelper()

{

//ReloadOnChange = true 当appsettings.json被修改时重新加载

_dbConnection = new SqlConnection();

_dbConnection.ConnectionString = new ConfigurationBuilder()

.SetBasePath(Directory.GetCurrentDirectory())

.AddJsonFile("appsettings.json").Build().GetConnectionString("Default");

}
    private static readonly IDbConnection _dbConnection;

    #region Query
public async Task&lt;T&gt; QueryFirstOrDefaultAsync&lt;T&gt;(string sql, object param = null, IDbTransaction transaction = null,
int? commandTimeout = null, CommandType? commandType = null)
{
return await _dbConnection.QueryFirstOrDefaultAsync&lt;T&gt;(sql, param, transaction, commandTimeout, commandType);
}
public T QueryFirstOrDefault&lt;T&gt;(string sql, object param = null, IDbTransaction transaction = null,
int? commandTimeout = null, CommandType? commandType = null)
{
return _dbConnection.QueryFirstOrDefault&lt;T&gt;(sql, param, transaction, commandTimeout, commandType);
}
public async Task&lt;List&lt;T&gt;&gt; QueryAsync&lt;T&gt;(string sql, object param = null, IDbTransaction transaction = null,
int? commandTimeout = null, CommandType? commandType = null)
{
return (await _dbConnection.QueryAsync&lt;T&gt;(sql, param, transaction, commandTimeout, commandType)).ToList();
}
public List&lt;T&gt; Query&lt;T&gt;(string sql, object param = null, IDbTransaction transaction = null,
bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
{
return _dbConnection.Query&lt;T&gt;(sql, param, transaction, buffered, commandTimeout, commandType).ToList();
}
#endregion #region Excute
public Task&lt;int&gt; ExecuteAsync(string sql, object param = null, IDbTransaction transaction = null,
int? commandTimeout = null, CommandType? commandType = null)
{
return _dbConnection.ExecuteAsync(sql, param, transaction, commandTimeout, commandType);
}
public int Execute(string sql, object param = null, IDbTransaction transaction = null,
int? commandTimeout = null, CommandType? commandType = null)
{
return _dbConnection.Execute(sql, param, transaction, commandTimeout, commandType);
} #endregion
}

}

使用:

using Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks; namespace dapperDemo

{

class Program

{

static async Task Main(string[] args)

{

#region 原生dapper封装

DapperHelper dapper = new DapperHelper();
        #region 查询集合

        Console.WriteLine("-----------------查询集合-------------------");
var students = await dapper.QueryAsync&lt;Student&gt;("select * from Student");
Console.WriteLine(JsonConvert.SerializeObject(students));
#endregion #region 单个查询
Console.WriteLine("-----------------单个查询-------------------");
string sql = "select * from student where StudentName=@StudentName";
var stu = await dapper.QueryFirstOrDefaultAsync&lt;Student&gt;(sql, new { StudentName = "小红帽" });
Console.WriteLine(JsonConvert.SerializeObject(stu));
#endregion #region 新增
Console.WriteLine("-----------------新增-------------------");
Student student = new Student()
{
Id = Guid.NewGuid(),
StudentName = "小红帽",
Sex = SexType.Male,
CreateTime = DateTime.Now,
IsDelete = false,
Birthday = DateTime.Now
};
string excuteSql = "insert into student(id,studentname,sex,createtime,isdelete,birthday)" +
" values(@Id,@StudentName,@Sex,@CreateTime,@IsDelete,@Birthday)";
var result = await dapper.ExecuteAsync(excuteSql, student);
Console.WriteLine(result);
#endregion #region 删除
Console.WriteLine("-----------------删除-------------------");
string deleteSql = "delete from student where studentname=@studentName";
var result = await dapper.ExecuteAsync(deleteSql, new {studentName = "小红帽"});
Console.WriteLine($"结果:{result}");
#endregion #region 修改
Console.WriteLine("-----------------修改-------------------");
string updateSql = "update student set studentname=@NewStudentName where studentName=@OldStudentName";
var result = await dapper.ExecuteAsync(updateSql, new {NewStudentName = "杜甫", OldStudentName = "李白" });
Console.WriteLine($"结果:{result}");
#endregion #endregion 原生dapper封装 }
}

}

三、Dapper的二次封装(基于上一个)

利用反射对Dapper进行二次封装:DapperSuperHelper<T>.cs,通过继承继承dapper的封装,我们可以即可用使用原始封装又可以使用通用的对单表的增删改查。

该封装可以实现对单个表的增删改查,以及分页查询,修改、删除、查询都是基于id查询,id支持任意类型。

注意:修改的时候建议先查出数据再执行修改,因为目前封装的代码无法实现只更改某个字段,暂时是全部更改,必填项必须有值。非必填,不传值,即为null。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks; namespace Model

{

public class DapperSuperHelper<T>:DapperHelper

{

/// <summary>

/// 查询所有

/// </summary>

/// <returns></returns>

public async Task<List<T>> GetAllAsync()

{

var sql = $"select * from {typeof(T).Name}";

return await QueryAsync<T>(sql);

}

public List<T> GetAll()

{

var sql = $"select * from {typeof(T).Name}";

return Query<T>(sql);

}

/// <summary>

/// 按id查询

/// </summary>

/// <param name="id"></param>

/// <returns></returns>

public T Get(object id)

{

var sql = $"select * from {typeof(T).Name} where id=@Id";

return QueryFirstOrDefault<T>(sql, new {Id = id});

}
    public async Task&lt;T&gt; GetAsync(object id)
{
var sql = $"select * from {typeof(T).Name} where id=@Id";
return await QueryFirstOrDefaultAsync&lt;T&gt;(sql, new { Id = id });
}
/// &lt;summary&gt;
/// 新增
/// &lt;/summary&gt;
/// &lt;param name="t"&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
public async Task&lt;int&gt; InsertAsync(T t)
{
Type type = t.GetType();
var sql = $"insert into {type.Name}" +
$"({string.Join(",",type.GetProperties().Select(n=&gt;n.Name))})"+
$" values({string.Join(",",type.GetProperties().Select(n=&gt;$"@{n.Name}"))})";
return await ExecuteAsync(sql,t);
}
public int Insert(T t)
{
Type type = t.GetType();
var sql = $"insert into {type.Name}" +
$"({string.Join(",", type.GetProperties().Select(n =&gt; n.Name))})" +
$" values({string.Join(",", type.GetProperties().Select(n =&gt; $"@{n.Name}"))})";
return Execute(sql, t);
}
/// &lt;summary&gt;
/// 修改
/// &lt;/summary&gt;
/// &lt;param name="t"&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
public async Task&lt;int&gt; UpdateAsync(T t)
{
Type type = t.GetType();
var sql = $"update {type.Name} set " +
$"{string.Join(",", type.GetProperties().Select(n =&gt; $"{n.Name}=@{n.Name}"))} " +
$"where id=@Id";
return await ExecuteAsync(sql,t);
}
public int Update(T t)
{
Type type = t.GetType();
var sql = $"update {type.Name} set " +
$"{string.Join(",", type.GetProperties().Select(n =&gt; $"{n.Name}=@{n.Name}"))} " +
$"where id=@Id";
return Execute(sql, t);
}
/// &lt;summary&gt;
/// 按id删除
/// &lt;/summary&gt;
/// &lt;param name="id"&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
public async Task&lt;bool&gt; DeleteAsync(object id)
{
var sql = $"delete from {typeof(T).Name} where id=@Id";
return await ExecuteAsync(sql, new { Id = id }) &gt; 0;
} public bool Delete(object id)
{
var sql = $"delete from {typeof(T).Name} where id=@Id";
return Execute(sql, new { Id = id }) &gt; 0;
}
/// &lt;summary&gt;
/// 删除全部
/// &lt;/summary&gt;
/// &lt;returns&gt;&lt;/returns&gt;
public async Task&lt;bool&gt; DeleteAllAsync()
{
var sql = $"delete from {typeof(T).Name}";
return await ExecuteAsync(sql) &gt; 0;
} public bool DeleteAll()
{
var sql = $"delete from {typeof(T).Name}";
return Execute(sql) &gt; 0;
}
/// &lt;summary&gt;
/// 单表分页查询
/// &lt;/summary&gt;
/// &lt;param name="pageIndex"&gt;&lt;/param&gt;
/// &lt;param name="pageSize"&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
public async Task&lt;List&lt;T&gt;&gt; GetPagedAsync(int pageIndex,int pageSize)
{
var skipRow = (pageIndex - 1) * pageSize;
var sql = $"select * from {typeof(T).Name} order by Id " +
$"offset @skipRow rows fetch next @PageSize rows only";
return await QueryAsync&lt;T&gt;(sql, new {skipRow, pageSize});
}
/// &lt;summary&gt;
/// 单表分页查询
/// &lt;/summary&gt;
/// &lt;param name="pageIndex"&gt;&lt;/param&gt;
/// &lt;param name="pageSize"&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
public List&lt;T&gt; GetPaged(int pageIndex, int pageSize)
{
var skipRow = (pageIndex - 1) * pageSize;
var sql = $"select * from {typeof(T).Name} order by Id " +
$"offset @skipRow rows fetch next @PageSize rows only";
return Query&lt;T&gt;(sql, new { skipRow, pageSize });
}
}

}

使用:

using Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks; namespace dapperDemo

{

class Program

{

static async Task Main(string[] args)

{
        #region dapper二次封装
DapperSuperHelper&lt;Student&gt; superDapper = new DapperSuperHelper&lt;Student&gt;();
//查询所有
List&lt;Student&gt; students = await superDapper.GetAllAsync();
Console.WriteLine(JsonConvert.SerializeObject(students)); //按id查询
var id = Guid.Parse("b2847592-90d6-40a4-b3b0-c1ebf514e258");
var stu = await superDapper.GetAsync(id);
Console.WriteLine(JsonConvert.SerializeObject(stu)); //新增
Student entity = new Student()
{
Id = Guid.NewGuid(),
Birthday = DateTime.Now,
CreateTime = DateTime.Now,
Email = "hello@163.com",
IsDelete = false,
Sex = SexType.Female,
StudentName = "夏花"
};
var result = await superDapper.InsertAsync(entity);
Console.WriteLine($"新增结果,受影响的行数:{result}"); //修改
entity.StudentName = "小燕子";
var updateResult = await superDapper.UpdateAsync(entity);
Console.WriteLine($"修改结果,受影响的行数:{updateResult}"); //删除
var did = Guid.Parse("b2847592-90d6-40a4-b3b0-c1ebf514e258");
var deleteResult = await superDapper.DeleteAsync(did);
Console.WriteLine($"删除结果:{deleteResult}"); //分页查询
var pagedResult = await superDapper.GetPagedAsync(2, 2);
Console.WriteLine(JsonConvert.SerializeObject(pagedResult));
#endregion }
}

}

四、Dapper官方提供的扩展包

原理和我通过反射进行的二次封装差不多,但是肯定比我写的更安全和规范、更复杂,不过官方的id我看了一下,好像只支持int类型。

可以看到我上面的二次封装和官方的封装其实差不多的功能,不过我还多了一个分页,嘿嘿。

using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Threading.Tasks;
using Dapper.Contrib.Extensions;
using Microsoft.Extensions.Configuration; namespace Model

{

public class DapperExtHelper<T> where T:class

{

static DapperExtHelper()

{

_dbConnection = new SqlConnection();

_dbConnection.ConnectionString = new ConfigurationBuilder()

.SetBasePath(Directory.GetCurrentDirectory())

.AddJsonFile("appsettings.json").Build().GetConnectionString("Default");

}
    private static readonly IDbConnection _dbConnection;

    public List&lt;T&gt; GetAll()
{
return _dbConnection.GetAll&lt;T&gt;().ToList();
}
public async Task&lt;List&lt;T&gt;&gt; GetAllAsync()
{
return (await _dbConnection.GetAllAsync&lt;T&gt;()).ToList();
}
public T Get(int id)
{
return _dbConnection.Get&lt;T&gt;(id);
} public bool Update(T entity)
{
return _dbConnection.Update(entity);
} public async Task&lt;bool&gt; UpdateAsync(T entity)
{
return await _dbConnection.UpdateAsync(entity);
}
public long Insert(T entity)
{
return _dbConnection.Insert(entity);
}
public async Task&lt;long&gt; InsertAsync(T entity)
{
return await _dbConnection.InsertAsync(entity);
} public bool Delete(T entity)
{
return _dbConnection.Delete(entity);
}
public async Task&lt;bool&gt; DeleteAsync(T entity)
{
return await _dbConnection.DeleteAsync(entity);
}
public bool DeleteAll()
{
return _dbConnection.DeleteAll&lt;T&gt;();
}
public async Task&lt;bool&gt; DeleteAllAsync()
{
return await _dbConnection.DeleteAllAsync&lt;T&gt;();
}
}

}

使用:

using Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks; namespace dapperDemo

{

class Program

{

static async Task Main(string[] args)

{
        #region dapper官方自带的扩展包
//查全部,官方默认会以类名后面加个s,我们最好指定[Table("Student")]
DapperExtHelper&lt;Student&gt; dapperExtHelper = new DapperExtHelper&lt;Student&gt;();
var students = dapperExtHelper.GetAll();
Console.WriteLine(JsonConvert.SerializeObject(students));
//id查询 只支持id为int
//var stu = dapperExtHelper.Get(1);
//删除全部
//dapperExtHelper.DeleteAll();
//删除
var delEntity = new Student()
{
Id = Guid.Parse("c066dfce-d7cd-46b5-9fa3-d0aa4b165dde")
};
//dapperExtHelper.Delete(delEntity);
//修改 全部字段修改,需要传递必填的参数,否则报错,未传的参数修改为空,因此最好是先查出当实体,再修改单独字段
var updEntity = new Student()
{
Id = Guid.Parse("b2847592-90d6-40a4-b3b0-c1ebf514e257"),
StudentName = "李白222",
CreateTime = DateTime.Now,
Birthday = DateTime.Now
};
dapperExtHelper.Update(updEntity);
//新增 这居然报错,id不能传null,就离谱,估计和类型有关
Student InsertEntity = new Student()
{
Id = Guid.NewGuid(),
Birthday = DateTime.Now,
CreateTime = DateTime.Now,
Email = "hello@163.com",
IsDelete = false,
Sex = SexType.Female,
StudentName = "夏花"
};
dapperExtHelper.Insert(InsertEntity); #endregion
}
}

}

以上就是我对dapper的简单的封装。大家也可以自行封装。

需要源代码的可以加群831181779@群主哦

Dapper的封装、二次封装、官方扩展包封装,以及ADO.NET原生封装的更多相关文章

  1. [ Laravel 5.5 文档 ] 官方扩展包 —— 全文搜索解决方案:Laravel Scout

    简介 Laravel Scout 为 Eloquent 模型全文搜索实现提供了简单的.基于驱动的解决方案.通过使用模型观察者,Scout 会自动同步更新模型记录的索引. 目前,Scout 通过 Alg ...

  2. laravel中使用的PDF扩展包——laravel-dompdf和laravel-snappy

    这两天项目中需要将HTML页面转换为PDF文件方便打印,我在网上搜了很多资料.先后尝试了laravel-dompdf和laravel-snappy两种扩展包,个人感觉laravel-snappy比较好 ...

  3. MTK官方SDK包编译openwrt

    全过程需要联网,最好有梯子,编译方式有两种 安装依赖库: apt-get install g++ apt-get install libncurses5-dev apt-get install zli ...

  4. 孟老板 BaseAdapter封装 (二) Healer,footer

    BaseAdapter封装(一) 简单封装 BaseAdapter封装(二) Header,footer BaseAdapter封装(三) 空数据占位图 BaseAdapter封装(四) PageHe ...

  5. Dapper基础知识二

    在下刚毕业工作,之前实习有用到Dapper?这几天新项目想用上Dapper,在下比较菜鸟,这块只是个人对Dapper的一种总结. 2,如何使用Dapper?     首先Dapper是支持多种数据库的 ...

  6. Laravel5中通过SimpleQrCode扩展包生成二维码实例

    Simple Qrcode是基于强大的Bacon/BaconQrCode库开发的针对Laravel框架的封装版本,用于在Laravel中为生成二维码提供接口. 安装SimpleQrCode扩展包 在项 ...

  7. WinDbg 命令三部曲:(二)WinDbg SOS 扩展命令手册

    本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 系列博文 <WinDbg 命令三部曲:(一)WinDbg 命令手册> <WinDb ...

  8. Windows下用Composer引入官方GitHub扩展包

    Windows下用Composer引入官方GitHub扩展包 1. 当你打开威武RC4版本的链接的时候,往下拉你可以看到这个,然后你要做的就是想到,百度Composer,看看是个什么鬼,别想太多,跟着 ...

  9. FreeSql 扩展包实现 Dapper 的使用习惯

    简介 FreeSql.Connection.Extensions 这是 FreeSql 衍生出来的扩展包,实现(Mysql/postgresql/sqlserver/Oracle/SQLite)数据库 ...

随机推荐

  1. vim编码设置(转)

    vim里面的编码主要跟三个参数有关:enc(encoding).fenc(fileencoding).fence(fileencodings) fenc是当前文件的编码,也就是说,一个在vim里面已经 ...

  2. Oracle学习笔记(1)

    折腾了好久 终于把oracle安装成功了.小兴奋下. 创建了一个数据库 dabook. run--> Services.msc查看服务: 可以看到DABOOK的服务已启动. 1,sys用户 在c ...

  3. "delete this" in C++

    Ideally delete operator should not be used for this pointer. However, if used, then following points ...

  4. node.js require() 源码解读

    时至今日,Node.js 的模块仓库 npmjs.com ,已经存放了15万个模块,其中绝大部分都是 CommonJS 格式.这种格式的核心就是 require 语句,模块通过它加载.学习 Node. ...

  5. 【Linux】【Services】【Disks】bftfs

    1. 简介 1.1 Btrfs(B-tree,Butter FS,Better FS) 1.2. 遵循GPL,由oracle在2007年研发,支持CoW 1.3. 主要为了替代早期的ext3/ext4 ...

  6. 关于ssh-keygen 生成的key以“BEGIN OPENSSH PRIVATE KEY”开头

    现在使用命令 ssh-keygen -t rsa  生成ssh,默认是以新的格式生成,id_rsa的第一行变成了"BEGIN OPENSSH PRIVATE KEY" 而不在是&q ...

  7. JDBCUtils工具类的属性

    package cn.itcast.util;import java.io.FileReader;import java.io.IOException;import java.net.URL;impo ...

  8. jupyter的使用技巧

    具体安装教程参见上一篇博客. 1.有几种格式code,编码模式:markdown注释格式: 2.如果出现no module named 'XX' ,需要在anaconda prompt中使用conda ...

  9. Set数据结构基本介绍

    构造 const set = new Set([1, 2, 3, 4, 4]); 可接受的参数为所有具有iterable 接口的数据 特性: 类似数组,无重复值. const set = new Se ...

  10. 转: iPhone屏幕尺寸、分辨率及适配

    1.iPhone尺寸规格 设备 iPhone 宽 Width 高 Height 对角线 Diagonal 逻辑分辨率(point) Scale Factor 设备分辨率(pixel) PPI 3GS ...