1、说明

本项目是一个使用.NET Standard 2.0开发的,基于 Dapper 的轻量级 ORM 框架,包含基本的CRUD以及根据表达式进行一些操作的方法,目前只针对单表,不包含多表连接操作。

github:https://github.com/iamoldli/NetSql

2、使用方法

2.2、安装

Install-Package NetSql

2.2、创建实体

创建Article实体类,继承EntityBase

public class Article : EntityBase
{
[Column("Title")]
public string Title1 { get; set; } public string Summary { get; set; } public string Body { get; set; } public Category Category { get; set; } public int ReadCount { get; set; } public bool IsDeleted { get; set; } public DateTime CreatedTime { get; set; }
} public enum Category
{
Blog,
Movie
}

EntityBase是一个定义好的实体基类,包含一个泛型主键标识,默认是 Int 类型的,也可以指定 long 或者 string 类型

 public class Article : EntityBase<string>

2.3、定义数据库上下文(DbContext)

数据库上下文我是模仿的 EF,IDbContextOptions是数据库上下文配置项接口,默认包含了 SqlServer 的实现DbContextOptions,如果使用的是 MySql 或者 SQLite,需要额外安装对应的扩展包

Install-Package NetSql.MySql //MySql
Install-Package NetSql.SQLite //SQLite

这里我定义了一个BlogDbContext上下文,其中包含一个Articles数据集

public class BlogDbContext : DbContext
{
public BlogDbContext(IDbContextOptions options) : base(options)
{
} public IDbSet<Article> Articles { get; set; }
}

2.4、数据集(DbSet)使用说明

2.4.1、创建数据库上下文实例

private readonly BlogDbContext _dbContext;
private readonly IDbSet<Article> _dbSet; public DbSetTests()
{
_dbContext = new BlogDbContext(new SQLiteDbContextOptions("Filename=./Database/Test.db"));
_dbSet = _dbContext.Set<Article>(); //预热
_dbSet.Find().First();
}

2.4.2、插入

[Fact]
public async void InsertTest()
{
var article = new Article
{
Title1 = "test",
Category = Category.Blog,
Summary = "这是一篇测试文章",
Body = "这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章",
ReadCount = 10,
IsDeleted = true,
CreatedTime = DateTime.Now
}; await _dbSet.InsertAsync(article); Assert.True(article.Id > 0);
}

2.4.3、批量插入

[Fact]
public void BatchInsertTest()
{
var sw = new Stopwatch();
sw.Start(); var tran = _dbContext.BeginTransaction(); for (var i = 0; i < 10000; i++)
{
var article = new Article
{
Title1 = "test" + i,
Category = i % 3 == 1 ? Category.Blog : Category.Movie,
Summary = "这是一篇测试文章",
Body = "这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章",
ReadCount = 10,
IsDeleted = i % 2 == 0,
CreatedTime = DateTime.Now
}; _dbSet.InsertAsync(article, tran);
} tran.Commit(); sw.Stop(); var s = sw.ElapsedMilliseconds; Assert.True(s > 0);
}

2.4.4、根据主键删除

[Fact]
public void DeleteTest()
{
var b = _dbSet.DeleteAsync(3).Result; Assert.True(b);
}

2.4.5、根据表达式删除

[Fact]
public async void DeleteWhereTest()
{
var b = await _dbSet.Find(m => m.Id > 10).Delete(); Assert.True(b);
} [Fact]
public async void DeleteWhereTest()
{
var b = await _dbSet.Find(m => m.Id > 10)
.Where(m => m.CreatedTime > DateTime.Now).Delete(); Assert.True(b);
}

2.4.6、修改

[Fact]
public async void UpdateTest()
{
var article = await _dbSet.Find().First();
article.Title1 = "修改测试"; var b = await _dbSet.UpdateAsync(article); Assert.True(b);
}

2.4.7、根据表达式修改实体部分属性

[Fact]
public async void UpdateWhereTest()
{
var b = await _dbSet.Find(m => m.Id == 1000).Update(m => new Article
{
Title1 = "hahahaah",
ReadCount = 1000
}); Assert.True(b);
}

2.4.8、根据主键查询单个实体

[Fact]
public void GetTest()
{
var article = _dbSet.GetAsync(100).Result; Assert.NotNull(article);
}

2.4.9、根据表达式查询单条数据

该方法返回结果集中的第一条数据

[Fact]
public async void GetWehreTest()
{
var article = await _dbSet.Find(m => m.Id > 100).First(); Assert.NotNull(article);
}

2.4.10、使用表达式

IDbSetFind方法会返回一个INetSqlQueryable对象,这个对象是模仿的 EF 里面的IQueryable,虽然有些不伦不类,但是是按照适合自己的方式设计的。

INetSqlQueryable目前包含以下方法:

  • Where:用于添加过滤条件
var query =  _dbSet.Find().Where(m => m.Id > 1);
  • WhereIf:根据指定条件来添加过滤条件
var query = _dbSet.Find().WhereIf(id > 1, m => m.Id > 200);
  • OrderBy:用于添加排序规则
var query = _dbSet.Find(m => m.Id > 200 && m.Id < 1000).OrderBy(m => m.Id, SortType.Desc);
  • Limit:该方法包含两个参数skiptake,标识跳过 skip 条数据,取 take 条数据
var query = _dbSet.Find(m => m.Id > 100 && m.Id < 120).Limit(5, 10);
  • Select:选择要返回的列
var query = _dbSet.Find().Select(m => new { m.Id, m.Title1 }).Limit(0, 10);

以上方法都是用于构造INetSqlQueryable的,下面的方法则是执行:

  • Max:查询最大值
var maxReadCount = _dbSet.Find().Max(m => m.ReadCount).Result;
  • Min:查询最小值
var maxReadCount = _dbSet.Find().Min(m => m.ReadCount).Result;
  • Count:查询数量
var count = _dbSet.Find(m => m.Id > 1000).Count().Result;
  • Exists:判断是否存在
var b = _dbSet.Find(m => m.Id > 1000).Exists().Result;
  • First:获取第一条数据
var article = _dbSet.Find(m => m.Id > 100 && m.Id < 120).First().Result;
  • Delete:删除数据
var b = _dbSet.Find(m => m.Id > 1000).Delete().Result;
  • Update:更新数据
var b = await _dbSet.Find(m => m.Id == 1000).Update(m => new Article
{
Title1 = "hahahaah",
ReadCount = 1000
});
  • ToList:获取结果集
var list = await _dbSet.Find(m => m.Id > 100 && m.Id < 120).ToList();

3、特性

表别名以及列名

[Table("blog_article")]
public class Article : EntityBase
{
[Column("Title")]
public string Title1 { get; set; } public string Summary { get; set; } public string Body { get; set; } public Category Category { get; set; } public int ReadCount { get; set; } public bool IsDeleted { get; set; } public DateTime CreatedTime { get; set; }
}

指定主键

可以通过KeyAttribute来指定某个字段为主键

4、泛型仓储(Repository)

平时开发时用到伪 DDD 比较多,所以框架提供了一个泛型仓储接口IRepository以及一个抽象实现RepositoryAbstract

/// <summary>
/// 判断是否存在
/// </summary>
/// <param name="where"></param>
/// <param name="transaction"></param>
/// <returns></returns>
Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> where, IDbTransaction transaction = null); /// <summary>
/// 新增
/// </summary>
/// <param name="entity">实体</param>
/// <param name="transaction">事务</param>
/// <returns></returns>
Task<bool> AddAsync(TEntity entity, IDbTransaction transaction = null); /// <summary>
/// 批量新增
/// </summary>
/// <param name="list"></param>
/// <param name="transaction"></param>
/// <returns></returns>
Task<bool> AddAsync(List<TEntity> list, IDbTransaction transaction = null); /// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <param name="transaction"></param>
/// <returns></returns>
Task<bool> DeleteAsync(dynamic id, IDbTransaction transaction = null); /// <summary>
/// 更新
/// </summary>
/// <param name="entity">实体</param>
/// <param name="transaction">事务</param>
/// <returns></returns>
Task<bool> UpdateAsync(TEntity entity, IDbTransaction transaction = null); /// <summary>
/// 根据主键查询
/// </summary>
/// <param name="id"></param>
/// <param name="transaction"></param>
/// <returns></returns>
Task<TEntity> GetAsync(dynamic id, IDbTransaction transaction = null); /// <summary>
/// 根据表达式查询单条记录
/// </summary>
/// <param name="where"></param>
/// <param name="transaction"></param>
/// <returns></returns>
Task<TEntity> GetAsync(Expression<Func<TEntity,bool>> where, IDbTransaction transaction = null); /// <summary>
/// 分页查询
/// </summary>
/// <param name="paging">分页</param>
/// <param name="where">过滤条件</param>
/// <param name="transaction">事务</param>
/// <returns></returns>
Task<List<TEntity>> PaginationAsync(Paging paging = null, Expression<Func<TEntity, bool>> where = null, IDbTransaction transaction = null);

RepositoryAbstract中包含实体对应的数据集IDbSet以及数据上限为IDbContext

protected readonly IDbSet<TEntity> Db;
protected readonly IDbContext DbContext; protected RepositoryAbstract(IDbContext dbContext)
{
DbContext = dbContext;
Db = dbContext.Set<TEntity>();
}

对于事务,建议使用工作单元IUnitOfWork

public interface IUnitOfWork
{
/// <summary>
/// 打开一个事务
/// </summary>
/// <returns></returns>
IDbTransaction BeginTransaction(); /// <summary>
/// 提交
/// </summary>
/// <returns></returns>
void Commit(); /// <summary>
/// 回滚
/// </summary>
void Rollback();
}

项目已经包含了一个实现UnitOfWork

6、仓储使用方法

6.1、定义仓储

public interface IArticleRepository : IRepository<Article>
{
}

6.2、创建仓储实例

private readonly IArticleRepository _repository;

public RepositoryTest()
{
var dbContext = new BlogDbContext(new SQLiteDbContextOptions("Filename=./Database/Test.db"));
_repository = new ArticleRepository(dbContext);
}

6.3、新增

[Fact]
public async void AddTest()
{
var article = new Article
{
Title1 = "test",
Category = Category.Blog,
Summary = "这是一篇测试文章",
Body = "这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章",
ReadCount = 10,
IsDeleted = true,
CreatedTime = DateTime.Now
}; await _repository.AddAsync(article); Assert.True(article.Id > 0);
}

6.4、批量增加

[Fact]
public void BatchInsertTest()
{
var list = new List<Article>();
for (var i = 0; i < 10000; i++)
{
var article = new Article
{
Title1 = "test" + i,
Category = i % 3 == 1 ? Category.Blog : Category.Movie,
Summary = "这是一篇测试文章",
Body = "这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章",
ReadCount = 10,
IsDeleted = i % 2 == 0,
CreatedTime = DateTime.Now
};
list.Add(article);
}
var sw = new Stopwatch();
sw.Start(); _repository.AddAsync(list); sw.Stop();
var s = sw.ElapsedMilliseconds; Assert.True(s > 0);
}

6.5、删除

[Fact]
public async void DeleteTest()
{
var b = await _repository.DeleteAsync(2); Assert.True(b);
}

6.6、修改

[Fact]
public async void UpdateTest()
{
var article = await _repository.GetAsync(2);
article.Title1 = "修改测试"; var b = await _repository.UpdateAsync(article); Assert.True(b);
}

6.7、分页查询

[Fact]
public async void PaginationTest()
{
var paging = new Paging(1, 20);
var list = await _repository.PaginationAsync(paging, m => m.Id > 1000); Assert.True(paging.TotalCount > 0);
}

未完待续~

分享自己写的基于Dapper的轻量级ORM框架~的更多相关文章

  1. 轻量级ORM框架初探-Dapper与PetaPoco的基本使用

    一.EntityFramework EF是传统的ORM框架,也是一个比较重量级的ORM框架.这里仍然使用EF的原因在于为了突出轻量级ORM框架的性能,所谓有对比才有更优的选择. 1.1 准备一张数据库 ...

  2. .NET轻量级ORM框架Dapper入门精通

    一.课程介绍 本次分享课程包含两个部分<.NET轻量级ORM框架Dapper修炼手册>和<.NET轻量级ORM框架Dapper葵花宝典>,阿笨将带领大家一起领略轻量级ORM框架 ...

  3. 轻量级ORM框架Dapper应用一:Dapper安装

    一.Dapper简介 Dapper是一款轻量级ORM框架,为解决网站访问流量极高而产生的性能问题而构造,主要通过执行TSQL表达式而实现数据库的CQRS. 如果你在项目中遇到性能访问问题,选择Dapp ...

  4. C# 性能优化 之 秒表 Stopwatch。 Dapper一个和petapoco差不多的轻量级ORM框架

    Sweet小马 小马同学的编程日记. C# 性能优化 之 秒表 Stopwatch. 生词解释:Diagnostics[,daɪəg'nɑstɪks] n.诊断学 using System.Diagn ...

  5. c# 轻量级ORM框架 实现(一)

    发布一个自己写的一个轻量级ORM框架,本框架设计期初基于三层架构.所以从命名上来看,了解三层的朋友会很好理解. 设计该框架的目的:不想重复的写增删改查,把精力放到功能实现上. 发布改框架的原因:希望给 ...

  6. 轻量级ORM框架 QX_Frame.Bantina(二、框架使用方式介绍)

    轻量级ORM框架QX_Frame.Bantina系列讲解(开源) 一.框架简介 http://www.cnblogs.com/qixiaoyizhan/p/7417467.html 二.框架使用方式介 ...

  7. 轻量级ORM框架 QX_Frame.Bantina(一、框架简介)

    轻量级ORM框架QX_Frame.Bantina系列讲解(开源) 一.框架简介 http://www.cnblogs.com/qixiaoyizhan/p/7417467.html 二.框架使用方式介 ...

  8. 基于.NET的微软ORM框架视频教程(Entity Framework技术)

    基于.NET的微软ORM框架视频教程(Entity Framework技术) 第一讲  ORM映射 第二讲 初识EntifyFramework框架 第三讲 LINQ表达式查询 第四讲 LINQ方法查询 ...

  9. 基于轻量级ORM框架Dapper的扩展说明

    这里简单的介绍一下本人基于Dapper作的一些简单的扩展,供大家参考. 为何要使用这款框架,相信大家看到下面排名就清楚了 其实在各大网站上,我们大概都会看到这样的一个对比效果图,在超过500次poco ...

随机推荐

  1. Linux Shell命令系列(2)

    6. history命令 “history”命令就是历史记录.它显示了在终端中所执行过的所有命令的历史. 7. sudo命令 “sudo”(super user do)命令允许授权用户执行超级用户或者 ...

  2. SQL中改变列的数据类型

    一.该列非主键.无default约束 直接更新: alter table 表名 alter column 列名 数据类型 二.该列为主键列.无default约束 (1)删除主键 alter table ...

  3. Cmder 简明使用说明

    简介 Cmder is a software package created out of pure frustration over the absence of nice console emul ...

  4. 原生ajax瀑布流demo

    最近听朋友们说起瀑布流挺多的,自己就去研究下了,一个简单的原生demo,分享给大家... 简单分为三个文档,有详细的注释:img:ajax.php:demo.php 其中img文件夹中放入图片 1.j ...

  5. 返回mapcontrol上的已被选择的element

     IGraphicsContainerSelect.SelectedElement

  6. javascript设计模式之中介者模式

    /* * 小游戏演示中介者模式 * Home 按键 1 * Guest 按键 0 * 半分钟内看谁按下的次数多 * * 参与的对象: * 玩家 * 计分板 * 中介者 * * 中介者模式使对象之间松耦 ...

  7. iOS开发 - 在状态栏显示FPS,CPU和内存信息

    原理 FPS的计算 CoreAnimation有一个很好用的类CADisplayLink,这个类会在每一帧绘制之前调用,并且可以获取时间戳.于是,我们只要统计出,在1s内的帧数即可. - (void) ...

  8. SqlServer图形数据库初体验

    SQL Server2017新增了一个新功能叫做图形数据库.图形指的拓扑图形,是一些Node表和Edge表的合集,Node对应关系数据库中的实体,比如一个人.一个岗位等,Edge表指示Node之前的关 ...

  9. C#环形缓冲区(队列)完全实现

    公司项目中经常设计到串口通信,TCP通信,而且大多都是实时的大数据的传输,然后大家都知道协议通讯肯定涉及到什么,封包.拆包.粘包.校验--什么鬼的概念一大堆,说简单点儿就是要一个高效率可复用的缓存区. ...

  10. 创建1M-1T的虚拟磁盘(内存盘)——使用破解版 Primo Ramdisk Server Edition v5.6.0

    破解版 Primo Ramdisk Server Edition v5.6.0下载: https://pan.lanzou.com/i0sgcne 步骤: 下载并解压后安装“Primo.Ramdisk ...