1、说明

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

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

2、使用方法

2.2、安装

  1. Install-Package NetSql

2.2、创建实体

创建Article实体类,继承EntityBase

  1. public class Article : EntityBase
  2. {
  3. [Column("Title")]
  4. public string Title1 { get; set; }
  5. public string Summary { get; set; }
  6. public string Body { get; set; }
  7. public Category Category { get; set; }
  8. public int ReadCount { get; set; }
  9. public bool IsDeleted { get; set; }
  10. public DateTime CreatedTime { get; set; }
  11. }
  12. public enum Category
  13. {
  14. Blog,
  15. Movie
  16. }

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

  1. public class Article : EntityBase<string>

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

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

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

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

  1. public class BlogDbContext : DbContext
  2. {
  3. public BlogDbContext(IDbContextOptions options) : base(options)
  4. {
  5. }
  6. public IDbSet<Article> Articles { get; set; }
  7. }

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

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

  1. private readonly BlogDbContext _dbContext;
  2. private readonly IDbSet<Article> _dbSet;
  3. public DbSetTests()
  4. {
  5. _dbContext = new BlogDbContext(new SQLiteDbContextOptions("Filename=./Database/Test.db"));
  6. _dbSet = _dbContext.Set<Article>();
  7. //预热
  8. _dbSet.Find().First();
  9. }

2.4.2、插入

  1. [Fact]
  2. public async void InsertTest()
  3. {
  4. var article = new Article
  5. {
  6. Title1 = "test",
  7. Category = Category.Blog,
  8. Summary = "这是一篇测试文章",
  9. Body = "这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章",
  10. ReadCount = 10,
  11. IsDeleted = true,
  12. CreatedTime = DateTime.Now
  13. };
  14. await _dbSet.InsertAsync(article);
  15. Assert.True(article.Id > 0);
  16. }

2.4.3、批量插入

  1. [Fact]
  2. public void BatchInsertTest()
  3. {
  4. var sw = new Stopwatch();
  5. sw.Start();
  6. var tran = _dbContext.BeginTransaction();
  7. for (var i = 0; i < 10000; i++)
  8. {
  9. var article = new Article
  10. {
  11. Title1 = "test" + i,
  12. Category = i % 3 == 1 ? Category.Blog : Category.Movie,
  13. Summary = "这是一篇测试文章",
  14. Body = "这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章",
  15. ReadCount = 10,
  16. IsDeleted = i % 2 == 0,
  17. CreatedTime = DateTime.Now
  18. };
  19. _dbSet.InsertAsync(article, tran);
  20. }
  21. tran.Commit();
  22. sw.Stop();
  23. var s = sw.ElapsedMilliseconds;
  24. Assert.True(s > 0);
  25. }

2.4.4、根据主键删除

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

2.4.5、根据表达式删除

  1. [Fact]
  2. public async void DeleteWhereTest()
  3. {
  4. var b = await _dbSet.Find(m => m.Id > 10).Delete();
  5. Assert.True(b);
  6. }
  7. [Fact]
  8. public async void DeleteWhereTest()
  9. {
  10. var b = await _dbSet.Find(m => m.Id > 10)
  11. .Where(m => m.CreatedTime > DateTime.Now).Delete();
  12. Assert.True(b);
  13. }

2.4.6、修改

  1. [Fact]
  2. public async void UpdateTest()
  3. {
  4. var article = await _dbSet.Find().First();
  5. article.Title1 = "修改测试";
  6. var b = await _dbSet.UpdateAsync(article);
  7. Assert.True(b);
  8. }

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

  1. [Fact]
  2. public async void UpdateWhereTest()
  3. {
  4. var b = await _dbSet.Find(m => m.Id == 1000).Update(m => new Article
  5. {
  6. Title1 = "hahahaah",
  7. ReadCount = 1000
  8. });
  9. Assert.True(b);
  10. }

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

  1. [Fact]
  2. public void GetTest()
  3. {
  4. var article = _dbSet.GetAsync(100).Result;
  5. Assert.NotNull(article);
  6. }

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

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

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

2.4.10、使用表达式

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

INetSqlQueryable目前包含以下方法:

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

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

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

3、特性

表别名以及列名

  1. [Table("blog_article")]
  2. public class Article : EntityBase
  3. {
  4. [Column("Title")]
  5. public string Title1 { get; set; }
  6. public string Summary { get; set; }
  7. public string Body { get; set; }
  8. public Category Category { get; set; }
  9. public int ReadCount { get; set; }
  10. public bool IsDeleted { get; set; }
  11. public DateTime CreatedTime { get; set; }
  12. }

指定主键

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

4、泛型仓储(Repository)

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

  1. /// <summary>
  2. /// 判断是否存在
  3. /// </summary>
  4. /// <param name="where"></param>
  5. /// <param name="transaction"></param>
  6. /// <returns></returns>
  7. Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> where, IDbTransaction transaction = null);
  8. /// <summary>
  9. /// 新增
  10. /// </summary>
  11. /// <param name="entity">实体</param>
  12. /// <param name="transaction">事务</param>
  13. /// <returns></returns>
  14. Task<bool> AddAsync(TEntity entity, IDbTransaction transaction = null);
  15. /// <summary>
  16. /// 批量新增
  17. /// </summary>
  18. /// <param name="list"></param>
  19. /// <param name="transaction"></param>
  20. /// <returns></returns>
  21. Task<bool> AddAsync(List<TEntity> list, IDbTransaction transaction = null);
  22. /// <summary>
  23. /// 删除
  24. /// </summary>
  25. /// <param name="id"></param>
  26. /// <param name="transaction"></param>
  27. /// <returns></returns>
  28. Task<bool> DeleteAsync(dynamic id, IDbTransaction transaction = null);
  29. /// <summary>
  30. /// 更新
  31. /// </summary>
  32. /// <param name="entity">实体</param>
  33. /// <param name="transaction">事务</param>
  34. /// <returns></returns>
  35. Task<bool> UpdateAsync(TEntity entity, IDbTransaction transaction = null);
  36. /// <summary>
  37. /// 根据主键查询
  38. /// </summary>
  39. /// <param name="id"></param>
  40. /// <param name="transaction"></param>
  41. /// <returns></returns>
  42. Task<TEntity> GetAsync(dynamic id, IDbTransaction transaction = null);
  43. /// <summary>
  44. /// 根据表达式查询单条记录
  45. /// </summary>
  46. /// <param name="where"></param>
  47. /// <param name="transaction"></param>
  48. /// <returns></returns>
  49. Task<TEntity> GetAsync(Expression<Func<TEntity,bool>> where, IDbTransaction transaction = null);
  50. /// <summary>
  51. /// 分页查询
  52. /// </summary>
  53. /// <param name="paging">分页</param>
  54. /// <param name="where">过滤条件</param>
  55. /// <param name="transaction">事务</param>
  56. /// <returns></returns>
  57. Task<List<TEntity>> PaginationAsync(Paging paging = null, Expression<Func<TEntity, bool>> where = null, IDbTransaction transaction = null);

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

  1. protected readonly IDbSet<TEntity> Db;
  2. protected readonly IDbContext DbContext;
  3. protected RepositoryAbstract(IDbContext dbContext)
  4. {
  5. DbContext = dbContext;
  6. Db = dbContext.Set<TEntity>();
  7. }

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

  1. public interface IUnitOfWork
  2. {
  3. /// <summary>
  4. /// 打开一个事务
  5. /// </summary>
  6. /// <returns></returns>
  7. IDbTransaction BeginTransaction();
  8. /// <summary>
  9. /// 提交
  10. /// </summary>
  11. /// <returns></returns>
  12. void Commit();
  13. /// <summary>
  14. /// 回滚
  15. /// </summary>
  16. void Rollback();
  17. }

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

6、仓储使用方法

6.1、定义仓储

  1. public interface IArticleRepository : IRepository<Article>
  2. {
  3. }

6.2、创建仓储实例

  1. private readonly IArticleRepository _repository;
  2. public RepositoryTest()
  3. {
  4. var dbContext = new BlogDbContext(new SQLiteDbContextOptions("Filename=./Database/Test.db"));
  5. _repository = new ArticleRepository(dbContext);
  6. }

6.3、新增

  1. [Fact]
  2. public async void AddTest()
  3. {
  4. var article = new Article
  5. {
  6. Title1 = "test",
  7. Category = Category.Blog,
  8. Summary = "这是一篇测试文章",
  9. Body = "这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章",
  10. ReadCount = 10,
  11. IsDeleted = true,
  12. CreatedTime = DateTime.Now
  13. };
  14. await _repository.AddAsync(article);
  15. Assert.True(article.Id > 0);
  16. }

6.4、批量增加

  1. [Fact]
  2. public void BatchInsertTest()
  3. {
  4. var list = new List<Article>();
  5. for (var i = 0; i < 10000; i++)
  6. {
  7. var article = new Article
  8. {
  9. Title1 = "test" + i,
  10. Category = i % 3 == 1 ? Category.Blog : Category.Movie,
  11. Summary = "这是一篇测试文章",
  12. Body = "这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章这是一篇测试文章",
  13. ReadCount = 10,
  14. IsDeleted = i % 2 == 0,
  15. CreatedTime = DateTime.Now
  16. };
  17. list.Add(article);
  18. }
  19. var sw = new Stopwatch();
  20. sw.Start();
  21. _repository.AddAsync(list);
  22. sw.Stop();
  23. var s = sw.ElapsedMilliseconds;
  24. Assert.True(s > 0);
  25. }

6.5、删除

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

6.6、修改

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

6.7、分页查询

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

未完待续~

分享自己写的基于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. Docker从入门到实战(三)

    Docker从入门到实战(三) 一:安装Docker 1. linux系统脚本安装 Docker基于linux容器技术,面向服务器端,Docker只能安装运行在64位计算机上(社区有对32位的支持), ...

  2. 源码分析Thread

    多次start ?? IlleageStateException

  3. spring boot(10) 基础学习内容

    A Spring boot(10) 基础学习内容 B SpringBoot(16) 基础学习内容

  4. js电话号码校验

    var contact_phone = $("#contact_phone").val();        if(contact_phone && /^1[3|4| ...

  5. Cucumber 场景大纲 Scenario Outlines

    引用链接:https://github.com/cucumber/cucumber/wiki/Scenario-Outlines script/cucumber --i18n zh-CN | feat ...

  6. hibernate课程 初探单表映射2-1 hibernate进阶 本章简介

    本章简介,主要讲5大块的内容 1 hibernate.cfg.xml的配置 2 session 的简介 3 transaction的简介 4 session的详解 5 对象关系映射常用配置

  7. swift 2特性记录

    swift 团队一直在优化,让大家准备在秋天的时候,迁移到swift2做准备. 一.错误处理 异常处理,不是NSError对象和双指针. 可以使用 throws   来指定方法来抛出一个错误. 调用d ...

  8. BZOJ2216: [Poi2011]Lightning Conductor(DP 决策单调性)

    题意 题目链接 Sol 很nice的决策单调性题目 首先把给出的式子移项,我们要求的$P_i = max(a_j + \sqrt{|i - j|}) - a_i$. 按套路把绝对值拆掉,$p_i = ...

  9. 报错:'byte' does not name a type

    这个错误是因为你在.cpp/.h中使用 byte 这个类型,把他修改成int就ok了

  10. 用户在设置密码时,提醒请输入半角字符(vue+element+valid)

    要保证callback()只有一个出口 rules:{ newPassword: [{validator:(rule,newPassword,callback)=>{ var all = fal ...