基于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.今天在这里 ...
随机推荐
- objectid.go源码阅读
)) } // func), ), ), ), ])<<])<<)]) } //获取])<<])<<])<<]), //转化为十进制的int ...
- 链表底层实现Java的Map(上)
链表实现Map public class LinkListMap<K,V> implements Map<K,V> { private class Node { public ...
- Spring Boot 入门教程 | 图文讲解
目录 一.Spring Boot 是什么 二.为什么要使用 Spring Boot 三.快速入门 3.1 创建 Spring Boot 项目 3.2 项目结构 3.3 引入 Web 依赖 3.4 编写 ...
- Python中pathlib模块
Python中pathlib模块 Path.cwd():返回当前目录的路径 Path.home():返回当前用户的家目录 Path.stat():返回此路径信息 Path.touch():创建文件 P ...
- .NETCore 千星项目模块化开发框架 SimplCommerce 详解
SimplCommerce 是 github 上过千星的.netcore 商城示例项目,本文详解他的模块化框架现实思路,其业务(如产品.订单)不作介绍.因作者文笔水平很差,它又很值得学习和推荐,就算不 ...
- Caffe源码理解1:Blob存储结构与设计
博客:blog.shinelee.me | 博客园 | CSDN Blob作用 据Caffe官方描述: A Blob is a wrapper over the actual data being p ...
- Vue.js 学习笔记 第5章 内置指令
本篇目录: 5.1 基本指令 5.2 条件渲染指令 5.3 列表渲染指令 v-for 5.4 方法与事件 5.5 实战:利用计算属性.指令等知识开发购物车 回顾一下第2.2节,我们己经介绍过指令(Di ...
- 一起学Android之Menu
概述 菜单(Menu)在Android开发中,是一种常见的用户界面组件,通过使用菜单Api可以给用户提供常见的一致的体验.本文主要讲解三种菜单的相关内容. 菜单的分类 选项菜单(OptionsMenu ...
- Java实现文本编辑时基于拼音输入的补全原型
续前文Java实现"命令式"简易文本编辑器原型. 效果如下: 所在源码库同上文, 尚未和上文的编辑器右侧的命令区集成. 代码由How to show autocomplete as ...
- 300+ Manual Testing and Selenium Interview Questions and Answers
Manual testing is a logical approach and automation testing complements it. So both are mandatory an ...