基于MongoDB.Driver的扩展
由于MongoDB.Driver中的Find方法也支持表达式写法,结合【通用查询设计思想】这篇文章中的查询思想,个人基于MongoDB扩展了一些常用的方法。
首先我们从常用的查询开始,由于MongoDB.Driver支持类似于AutoMapper返回的指定属性(Project<TDto>方法),所以这里都是基于泛型的扩展
查询
/// <summary>
/// 同步查询指定条件的数据,并且返回指定类型TDto
/// </summary>
/// <typeparam name="TEntity">查询实体</typeparam>
/// <typeparam name="TDto">返回类型</typeparam>
/// <param name="source"></param>
/// <param name="query"></param>
public static IFindFluent<TEntity, TDto> FindSync<TEntity, TDto>(this IMongoCollection<TEntity> source, IQuery<TEntity> query)
where TEntity : class
{
var projection = GetTDtoReturnProperties<TEntity, TDto>(); var expression = query?.GenerateExpression();
if (null == expression)
{
var emptyExpression = Builders<TEntity>.Filter.Empty;
return source.Find(emptyExpression).Project<TDto>(projection);
} return source.Find(expression).Project<TDto>(projection);
} /// <summary>
/// 获取指定的返回列
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TDto"></typeparam>
/// <returns></returns>
private static ProjectionDefinition<TEntity, TDto> GetTDtoReturnProperties<TEntity, TDto>()
where TEntity : class
{
var returnType = typeof(TDto); var fieldList = new List<ProjectionDefinition<TEntity>>();
foreach (var property in returnType.GetProperties())
{
fieldList.Add(Builders<TEntity>.Projection.Include(property.Name));
} return Builders<TEntity>.Projection.Combine(fieldList);
}
这里主要是利用了IQuery接口中的GenerateExpression方法,如果前端传来了查询参数,则拼装返回我们的表达式,如果没有,默认返回一个空的Filter,再通过Project<TDto>映射关系到TDto上。
排序
/// <summary>
/// 排序方法
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TDto"></typeparam>
/// <param name="source"></param>
/// <param name="sortInfo"></param>
/// <returns></returns>
public static IFindFluent<TEntity, TDto> Sort<TEntity, TDto>(this IFindFluent<TEntity, TDto> source, ISortInfo sortInfo)
where TEntity : class
{
var sort = Builders<TEntity>.Sort;
SortDefinition<TEntity> sortDefinition = null;
if (sortInfo != null)
{
if (!string.IsNullOrWhiteSpace(sortInfo.Order) && !string.IsNullOrWhiteSpace(sortInfo.Field))
{
if (sortInfo.Order.Contains("asc"))
sortDefinition = sort.Ascending(sortInfo.Field);
if (sortInfo.Order.Contains("desc"))
sortDefinition = sort.Descending(sortInfo.Field);
}
} return source.Sort(sortDefinition);
}
这里前端是使用了LayUI的表格,所以API中的参数是Order和Field,我们也可以结合例如JQuery的DataTable或者其他框架的表格,只是参数SortInfo稍微不一样,大家结合实际情况来更改业务即可。
分页
/// <summary>
/// 查询指定条件的数据
/// </summary>
/// <typeparam name="TEntity">查询的实体</typeparam>
/// <typeparam name="TDto">返回的类型</typeparam>
/// <param name="source"></param>
/// <param name="query">查询条件</param>
/// <param name="page">分页信息</param>
public static async Task<PageResult<TDto>> ToPageResultAsync<TEntity, TDto>(this IMongoCollection<TEntity> source, IQuery<TEntity> query, IPageInfo page)
where TEntity : class
{
var pageIndex = Math.Max(, page.PageIndex);
var pageSize = Math.Max(, page.PageSize); var cursor = source.FindSync<TEntity, TDto>(query); var pageResult = new PageResult<TDto>
{
PageIndex = pageIndex,
PageSize = pageSize,
TotalCount = (int)await cursor.CountDocumentsAsync(),
Data = await cursor.Skip(pageSize * (pageIndex - )).Limit(pageSize).Sort(page).ToListAsync()
}; return pageResult;
}
增和删暂时不写了,官方API也提供了批处理的接口,都可以直接用的。
来看一下我们这几个扩展方法的应用(基于aspnet core)
public class MongoHelper
{
private static readonly string DbName = ConfigHelper.GetSetting("MongoDb").ToString();
private static readonly string ConnStr = ConfigHelper.GetSetting("MongoDbConnStr").ToString();
private static IMongoDatabase Db { get; } private static readonly object LockHelper = new object(); #region cotr static MongoHelper()
{
if (Db == null)
{
lock (LockHelper)
{
if (Db == null)
{
var client = new MongoClient(ConnStr);
Db = client.GetDatabase(DbName);
}
}
}
} #endregion #region query /// <summary>
/// 查询一个集合中的所有数据 其集合的名称为T的名称
/// </summary>
/// <typeparam name="TEntity">该集合数据的所属类型</typeparam>
/// <typeparam name="TDto">返回类型</typeparam>
/// <returns>返回一个Result<TDto />
/// </returns>
public static async Task<Result<TDto>> QueryAsync<TEntity, TDto>(IQuery<TEntity> query, string collectionName = "")
where TEntity : class
{
//检查是否存在该文档
var existed = await CollectionExists(Db, string.IsNullOrWhiteSpace(collectionName) ? DbName : collectionName);
if (existed)
{
var collection = Db.GetCollection<TEntity>(string.IsNullOrWhiteSpace(collectionName) ? DbName : collectionName);
var result = collection.FindSync<TEntity, TDto>(query);
var listResult = await result.ToListAsync();
return Result.FromData(listResult.FirstOrDefault());
}
else
{
return Result.FromCode<TDto>(ResultCode.NoSuchCollection);
}
} /// <summary>
/// 查询一个集合中的所有数据 其集合的名称为T的名称
/// </summary>
/// <typeparam name="TEntity">该集合数据的所属类型</typeparam>
/// <typeparam name="TDto">返回数据类型</typeparam>
/// <returns>返回一个List列表</returns>
public static async Task<Result<List<TDto>>> QueryListAsync<TEntity, TDto>(IQuery<TEntity> query, string collectionName = "")
where TEntity : class
{
var collection = Db.GetCollection<TEntity>(string.IsNullOrWhiteSpace(collectionName) ? DbName : collectionName);
var result = collection.FindSync<TEntity, TDto>(query);
var listResult = await result.ToListAsync();
return Result.FromData(listResult);
} /// <summary>
/// 分页方法
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TDto"></typeparam>
/// <param name="collectionName">指定文档名称</param>
/// <param name="query"></param>
/// <returns></returns>
public static async Task<PageResult<TDto>> QueryPageResultAsync<TEntity, TDto>(PageQuery<TEntity> query, string collectionName = "")
where TEntity : class
{
//检查是否存在该文档
var existed = await CollectionExists(Db, string.IsNullOrWhiteSpace(collectionName) ? DbName : collectionName);
if (existed)
{
var collection = Db.GetCollection<TEntity>(string.IsNullOrWhiteSpace(collectionName) ? DbName : collectionName);
return await collection.ToPageResultAsync<TEntity, TDto>(query, query);
}
else
{
return new PageResult<TDto>
{
Code = ResultCode.NoSuchCollection
};
}
} #endregion #region Private Methods /// <summary>
/// 检查是否存在该文档
/// </summary>
/// <param name="database">指定的数据库</param>
/// <param name="collectionName">文档名称</param>
/// <returns></returns>
private static async Task<bool> CollectionExists(IMongoDatabase database, string collectionName)
{
var options = new ListCollectionsOptions
{
Filter = Builders<BsonDocument>.Filter.Eq("name", collectionName)
}; return await database.ListCollections(options).AnyAsync();
}
#endregion
}
有了这个帮助类,我们可以看一下应用层的具体应用
/// <summary>
/// TEntity的分页查询
/// </summary>
/// <typeparam name="TEntity">查询实体</typeparam>
/// <typeparam name="TDto">返回结果</typeparam>
/// <param name="query">查询条件</param>
/// <returns></returns>
public async Task<PageResult<TDto>> GetPagedLogsAsync<TEntity, TDto>(PageQuery<TEntity> query)
where TEntity : class
{
return await MongoHelper.QueryPageResultAsync<TEntity, TDto>(query, typeof(TEntity).Name);
} /// <summary>
/// TEntity的查询
/// </summary>
/// <typeparam name="TEntity">查询实体</typeparam>
/// <typeparam name="TDto">返回结果</typeparam>
/// <param name="query">查询条件</param>
/// <returns></returns>
public async Task<Result<TDto>> GetSpecifyLogAsync<TEntity, TDto>(IQuery<TEntity> query)
where TEntity : class
{
return await MongoHelper.QueryAsync<TEntity, TDto>(query, typeof(TEntity).Name);
}
看一下我们Controller的调用
/// <summary>
/// 获取指定条件的日志分页列表
/// </summary>
/// <param name="query">查询参数</param>
/// <returns></returns>
[HttpPost]
public async Task<PageResult<LogResult>> SearchPagedLogsAsync(LogPageQuery query)
{
return await _logBll.GetPagedLogsAsync<Log, LogResult>(query);
} /// <summary>
/// 获取指定条件的日志
/// </summary>
/// <param name="id">查询参数</param>
/// <returns></returns>
public async Task<Result<LogResult>> GetLogByIdAsync(string id)
{
if (string.IsNullOrWhiteSpace(id))
return Result.FromCode<LogResult>(ResultCode.Fail);
return await _logBll.GetSpecifyLogAsync<Log, LogResult>(new Query<Log>(m => m.Id == new ObjectId(id)));
}
我这里的例子是为了符合单一职责的设计原则,所以指定了GetLogByIdAsync这样的单一接口,如果大家喜欢单个方法满足更多功能,可以参照【通用查询设计思想】文章中的Controller写法。
让我知道你们有更好的想法!
基于MongoDB.Driver的扩展的更多相关文章
- 扩展 MongoDB.Driver 支持实体
针对MongoDB的官方C#驱动进行扩展 一.安装 Install-Package Apteryx.MongoDB.Driver.Extend 移步我的项目https://github.com/cod ...
- 适用于app.config与web.config的ConfigUtil读写工具类 基于MongoDb官方C#驱动封装MongoDbCsharpHelper类(CRUD类) 基于ASP.NET WEB API实现分布式数据访问中间层(提供对数据库的CRUD) C# 实现AOP 的几种常见方式
适用于app.config与web.config的ConfigUtil读写工具类 之前文章:<两种读写配置文件的方案(app.config与web.config通用)>,现在重新整理一 ...
- MongoDB入门及 c# .netcore客户端MongoDB.Driver使用
MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系 ...
- centos yum 安装 mongodb 以及php扩展
centos yum 安装 mongodb 以及php扩展 投稿:hebedich 字体:[增加 减小] 类型:转载 MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用 ...
- 基于Mongodb的轻量级领域驱动框架(序)
混园子也有些年头了,从各个大牛那儿学了很多东西.技术这东西和中国的料理一样,其中技巧和经验,代代相传(这不是舌尖上的中国广告).转身回头一望,几年来自己也积累了一些东西,五花八门涉猎到各种方向,今日开 ...
- 基于MongoDB打造.Net的分布式Session子系统
基于MongoDB打造.Net的分布式Session子系统 Taobao有她自己的分布式session框架,.net阵营也不能落后了,在下做了个基于MongoDB的支持最多26台MongoDB的分布式 ...
- 基于MongoDb官方C#驱动封装MongoDbCsharpHelper类(CRUD类)
近期工作中有使用到 MongoDb作为日志持久化对象,需要实现对MongoDb的增.删.改.查,但由于MongoDb的版本比较新,是2.4以上版本的,网上已有的一些MongoDb Helper类都是基 ...
- C# .NET Core 3.1中使用 MongoDB.Driver 更新嵌套数组元素和关联的一些坑
C# .NET Core 3.1中使用 MongoDB.Driver 更新数组元素和关联的一些坑 前言: 由于工作的原因,使用的数据库由原来的 关系型数据库 MySQL.SQL Server 变成了 ...
- 基于Spring的可扩展Schema进行开发自定义配置标签支持
一.背景 最近和朋友一起想开发一个类似alibaba dubbo的功能的工具,其中就用到了基于Spring的可扩展Schema进行开发自定义配置标签支持,通过上网查资料自己写了一个demo.今天在这里 ...
随机推荐
- MyBatis的增删改查。
数据库的经典操作:增删改查. 在这一章我们主要说明一下简单的查询和增删改,并且对程序接口做了一些调整,以及对一些问题进行了解答. 1.调整后的结构图: 2.连接数据库文件配置分离: 一般的程序都会把连 ...
- 打包前端WebSite到Go程序
打包前端WebSite到Go程序 Coolpy5发布在即,新版本要求服务端程序只是一个运行文件,经历了go的template无数坑后,最后还是放弃了,所以还是要把前端独立开发一个纯前端程序,但是go程 ...
- C++11标准中常用到的各种算法汇总.
在C++11标准中定义了很多算法,这些算法可以让我们很方便的操作各种容器和数组,这里要注意一下,这些算法操作的并非容器,而是迭代器,然后通过迭代器来操作容器中的数据,算法本身并不会关注容器中保存的数据 ...
- NOIP2017 酱油送命记
Day0 一天,在机房,有点考前的紧张和慌张,打了一下午的模板,立了3个不该立的flag... Day1 拿到试题,万分紧张,T1是数论啊 害怕,一直以为D2T1才是数论,仔细观察却发现(flag1: ...
- Spring Boot 2.0 图文教程 | 集成邮件发送功能
文章首发自个人微信公众号: 小哈学Java 个人网站: https://www.exception.site/springboot/spring-boots-send-mail 大家好,后续会间断地奉 ...
- .NET Core IdentityServer4实战-开篇介绍与规划
一.开篇寄语 由于假期的无聊,我决定了一个非常有挑战性的活动,也就是在年假给大家带来一个基于OAuth 2.0的身份授权框架,它就是 IdentityServer4 ,如果没有意外的话,一定可以顺利的 ...
- ab性能测试工具的使用
一.什么是ab ab,即Apache Benchmark,是一种用于测试Apache超文本传输协议(HTTP)服务器的工具. ab命令会创建很多的并发访问线程,模拟多个访问者同时对某一URL地址进行访 ...
- 整合X-Admin前端框架改造ABP
“站在巨人的肩膀上”,这样一来,不要万事亲恭,在值得的方向上节约时间,毕竟人生就这么一次.在接触ABP以来,一直想花点时间整合LayUI前端框架到ABP中,进而能够逐渐打磨出一套适合自己的框架,开发习 ...
- [翻译 EF Core in Action 2.1] 设置一个图书销售网站的场景
Entity Framework Core in Action Entityframework Core in action是 Jon P smith 所著的关于Entityframework Cor ...
- 零基础学Python--------第3章 流程控制语句
第3章 流程控制语句 3.1程序的结构 计算机在解决某个具体问题时,主要有3种情况,分别是顺序执行所有的语句.选择执行部分语句和循环执行部分语句.程序设计中的3种基本结构为顺序结构.选择结构和循环结构 ...