基于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.今天在这里 ...
随机推荐
- 【构造】Bzoj1432[ZJOI2009]Function
Description Input 一行两个整数n; k. Output 一行一个整数,表示n 个函数第k 层最少能由多少段组成. Sample Input 1 1 Sample Output 1 ...
- BZOJ_2303_[Apio2011]方格染色 _并查集
BZOJ_2303_[Apio2011]方格染色 _并查集 Description Sam和他的妹妹Sara有一个包含n × m个方格的 表格.她们想要将其的每个方格都染成红色或蓝色. 出于个人喜好, ...
- BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法
BZOJ_4818_[Sdoi2017]序列计数_矩阵乘法 Description Alice想要得到一个长度为n的序列,序列中的数都是不超过m的正整数,而且这n个数的和是p的倍数.Alice还希望 ...
- BZOJ_1486_[HNOI2009]最小圈_01分数规划
BZOJ_1486_[HNOI2009]最小圈_01分数规划 Description Input Output Sample Input 4 5 1 2 5 2 3 5 3 1 5 2 4 3 4 1 ...
- POJ1038 Bugs Integrated, Inc 状压DP+优化
(1) 最简单的4^10*N的枚举(理论上20%) (2) 优化优化200^3*N的枚举(理论上至少50%) (3) Dfs优化状压dp O(我不知道,反正过不了,需要再优化)(理论上80%) (4) ...
- 开源方案搭建可离线的精美矢量切片地图服务-2.PostGIS+GeoServer矢量切片
项目成果展示(所有项目文件都在阿里云的共享云虚拟主机上,访问地图可以会有点慢,请多多包涵). 01:中国地图:http://test.sharegis.cn/mapbox/html/3china.ht ...
- UWP中实现大爆炸效果(一)
自从老罗搞出大爆炸之后,各家安卓都内置了类似功能.UWP怎么能落下呢,在这里我们就一起撸一个简单的大爆炸实现. 闲话不说,先上效果: 因为代码太多,所以我打算写成一个系列,下面是第一篇的正文: 首先, ...
- FTRL(Follow The Regularized Leader)学习总结
摘要: 1.算法概述 2.算法要点与推导 3.算法特性及优缺点 4.注意事项 5.实现和具体例子 6.适用场合 内容: 1.算法概述 FTRL是一种适用于处理超大规模数据的,含大量稀疏特征的在线学习的 ...
- 移动通信最先进的音频编解码器EVS及用好要做的工作
语音通信从最初的只有有线通信变成后来的有线通信与无线通信(移动通信)的竞争,当移动语音通信价格下来后有线语音通信明显处于逆势.如今移动语音通信的竞争对手是OTT(On The Top)语音,OTT语音 ...
- Python基础练习题100例(Python 3.x)
1:题目:有四个数字:1.2.3.4,能组成多少个互不相同且无重复数字的三位数?各是多少? 程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. 程序源 ...