分享自己写的基于Dapper的轻量级ORM框架~
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、使用表达式
IDbSet
的Find
方法会返回一个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
:该方法包含两个参数skip
和take
,标识跳过 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框架~的更多相关文章
- 轻量级ORM框架初探-Dapper与PetaPoco的基本使用
一.EntityFramework EF是传统的ORM框架,也是一个比较重量级的ORM框架.这里仍然使用EF的原因在于为了突出轻量级ORM框架的性能,所谓有对比才有更优的选择. 1.1 准备一张数据库 ...
- .NET轻量级ORM框架Dapper入门精通
一.课程介绍 本次分享课程包含两个部分<.NET轻量级ORM框架Dapper修炼手册>和<.NET轻量级ORM框架Dapper葵花宝典>,阿笨将带领大家一起领略轻量级ORM框架 ...
- 轻量级ORM框架Dapper应用一:Dapper安装
一.Dapper简介 Dapper是一款轻量级ORM框架,为解决网站访问流量极高而产生的性能问题而构造,主要通过执行TSQL表达式而实现数据库的CQRS. 如果你在项目中遇到性能访问问题,选择Dapp ...
- C# 性能优化 之 秒表 Stopwatch。 Dapper一个和petapoco差不多的轻量级ORM框架
Sweet小马 小马同学的编程日记. C# 性能优化 之 秒表 Stopwatch. 生词解释:Diagnostics[,daɪəg'nɑstɪks] n.诊断学 using System.Diagn ...
- c# 轻量级ORM框架 实现(一)
发布一个自己写的一个轻量级ORM框架,本框架设计期初基于三层架构.所以从命名上来看,了解三层的朋友会很好理解. 设计该框架的目的:不想重复的写增删改查,把精力放到功能实现上. 发布改框架的原因:希望给 ...
- 轻量级ORM框架 QX_Frame.Bantina(二、框架使用方式介绍)
轻量级ORM框架QX_Frame.Bantina系列讲解(开源) 一.框架简介 http://www.cnblogs.com/qixiaoyizhan/p/7417467.html 二.框架使用方式介 ...
- 轻量级ORM框架 QX_Frame.Bantina(一、框架简介)
轻量级ORM框架QX_Frame.Bantina系列讲解(开源) 一.框架简介 http://www.cnblogs.com/qixiaoyizhan/p/7417467.html 二.框架使用方式介 ...
- 基于.NET的微软ORM框架视频教程(Entity Framework技术)
基于.NET的微软ORM框架视频教程(Entity Framework技术) 第一讲 ORM映射 第二讲 初识EntifyFramework框架 第三讲 LINQ表达式查询 第四讲 LINQ方法查询 ...
- 基于轻量级ORM框架Dapper的扩展说明
这里简单的介绍一下本人基于Dapper作的一些简单的扩展,供大家参考. 为何要使用这款框架,相信大家看到下面排名就清楚了 其实在各大网站上,我们大概都会看到这样的一个对比效果图,在超过500次poco ...
随机推荐
- @RequestBody注解的用法
以前,一直以为在SpringMVC环境中,@RequestBody接收的是一个Json对象,一直在调试代码都没有成功,后来发现,其实 @RequestBody接收的是一个Json对象的字符串,而不是一 ...
- mysql隔离级别与锁,接口并发响应速度的关系(2)
innoDB默认隔离级别 mysql> SELECT @@tx_isolation; +-----------------+ | @@tx_isolation | +-------------- ...
- java——helloword
第一次接触Java,感觉乱乱的,需要捋清楚一些概念再安装java. 首先,什么是JDK,什么是JRE呢? JRE:JAVA运行环境(Java Runtime Envirnment) JDK:Java开 ...
- python入门之paramiko模块
paramiko用于实现ssh远程连接服务器执行相关操作. paramiko与之依赖模块cryptography最好版本相同,不然可能执行程序会出错. 一.ssh连接服务器执行命令 import pa ...
- Win10创建还原点
Win + E打开任务管理器 右击此电脑,选择属性 单击高级系统设置 选择系统保护 单击系统还原 按照提示操作,OK.
- Android图表库XCL-Charts
首先,这个是国人开发的,支持下必须顶!github项目地址:点击打开,由于项目的基本功能已经实现,所以项目作者也说以后基本不会在有更新了. 项目简介: Android图表库(XCL-Charts is ...
- Android Service创建USB HOST通信
之前做了一个关于Android USB通信的Case,通过Android的USB总线给Zigbee供电,和板载的Zigbee(基于Zigbee的自组网)进行通信.要使用Android的USB Host ...
- Java基础反射-调用类
Student类 package com.test.wang; import java.lang.reflect.Constructor; import java.lang.reflect.Field ...
- spring-boot整合shiro作权限认证
spring-shiro属于轻量级权限框架,即使spring-security更新换代,市场上大多数企业还是选择shiro 废话不多说 引入pom文件 <!--shiro集成spring--& ...
- 从零开始的全栈工程师——js篇2.2
条件语句 补充: var a=“hello world” a这个变量是字符串了 对于里面每一个字母来说 他是字节 里面有11个字节 字节总数用length表示 如下: 根据上面的内容咱们又发现了一个运 ...