基于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.今天在这里 ...
随机推荐
- Java 中的纤程库 – Quasar
来源:鸟窝, colobu.com/2016/07/14/Java-Fiber-Quasar/ 如有好文章投稿,请点击 → 这里了解详情 最近遇到的一个问题大概是微服务架构中经常会遇到的一个问题: 服 ...
- go源文件中是否有main函数
import ( "go/parser" "go/token" "go/ast" ) func HasMain(file s ...
- poj 3687
Description Windy has N balls of distinct weights from 1 unit to N units. Now he tries to label them ...
- cmd 【已解决】windows连接手机,运行adb devices提示“unauthorized”
报错截图如下: 问题原因:电脑连接手机.手机未授权 解决方式: 设置----开发者选项-----打开USB调试,出现如下弹框,点击"确定"即可解决问题.
- Python-炫酷二维码
一.环境 首先是安装python环境,如果没有安装python环境看此处 二.myqr myqr 其实是一个 python 的脚本,可以生产二维码图片,作者也对python脚本进行了打包,在 ...
- XiaomiPushDemo【小米推送集成,基于V3.6.12版本】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 这个Demo只是记录小米推送的集成,不能运行. 使用步骤 一.项目组织结构图 注意事项: 1. 导入类文件后需要change包名以 ...
- aps .net MVC单用户登录
当不允许多用户同时登录一个帐号时,就需要一种机制,当再登录一个相同的帐号时,前面登录的人被挤下线. 原文地址:http://www.cnblogs.com/f23wangj/p/4984302.htm ...
- 第2章 授权端点(Authorize Endpoint) - IdentityModel 中文文档(v1.0.0)
对于大多数情况,OAuth 2.0和OpenID Connect授权端点的GET请求需要具有许多查询字符串参数. 虽然您可以使用任何方法创建带参数的URL来创建正确的字符串,但RequestUrl类是 ...
- java监听器简述
监听器的概念 所谓监听器就是对内置对象的状态或者属性变化进行监听并且做出反应的特殊servlet,并且也需要在web.xml文件中进行相关配置. 内置对象的状态变化:初始化和销毁,也就是说当内置对象初 ...
- 【表格】大于号转义符&gt;---小于号转义符&lt;
关于来源:百度及个人经验. 常用的都是个人尝试过或个人常用的,其它的都是从百度来的.使用前建议写个HTML的Demo试试看 ^_^ 比心 < < < 小于号 > > &g ...