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. HashMap遍历时的性能对比

    使用KeySet和EntrySet遍历的差别 public static void main(String[] args) { HashMap<Integer, Integer> hasM ...

  2. 去除 Git 安装后的右键菜单

    64位 windows 8.1 安装 Git 后,右键菜单多了3个选项(Git Init Here,Git Gui, Git Bash),但是用不着,需要删掉.方法如下: 1.在 CMD 中进入 Gi ...

  3. $.getScript("/Scripts/js/video.min.js");

    js内引用JS: $.getScript("/Scripts/js/video.min.js");

  4. 自动生成actionbar 所需图片和style

    http://jgilfelt.github.io/android-actionbarstylegenerator/

  5. Shell 学习—AWK介绍

    Shell 学习—AWK = = = 安装awk root@kiki-desktop:~/shell# apt-get install gawk gawk-doc = = = awk 是一种程序语言. ...

  6. Cache 和 Buffer 区别是什么

    一 从常识来说,cache叫缓存,buffer叫缓冲. 二 尴尬的是缓存是什么?缓冲是什么? 缓冲,缓和冲击.也就是100次保存数据库,先把操作保存到本地,然后满10次才保存到数据库. 缓存,就是缓冲 ...

  7. springcloud 之 feign的重复性调用 优化

    最近有一个springcloud的feign请求,用于获取坐标经纬度的信息,返回结果永远是固定不变的,所以考虑优化一下,不然每次转换几个坐标都要去请求feign,返回的所有坐标信息,数据量太大导致耗时 ...

  8. css盒子模型 css3盒子相关样式

    1.内边距(内边距在content外,边框内) 内边距属性: padding          设置所有边距 padding-bottom     底边距 padding-left           ...

  9. CF1174D Ehab and the Expected XOR Problem

    思路: 使用前缀和技巧进行问题转化:原数组的任意子串的异或值不能等于0或x,可以转化成前缀异或数组的任意两个元素的异或值不能等于0或x. 实现: #include <bits/stdc++.h& ...

  10. #include stdio.h(2)

    #include <stdio.h> //mian函数是程序的入口 int main() { /* //函数:是按一定的格式对一段代码的封装 //专门用来实现一功能的代码合集,可以重复使用 ...