由于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的扩展的更多相关文章

  1. 扩展 MongoDB.Driver 支持实体

    针对MongoDB的官方C#驱动进行扩展 一.安装 Install-Package Apteryx.MongoDB.Driver.Extend 移步我的项目https://github.com/cod ...

  2. 适用于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通用)>,现在重新整理一 ...

  3. MongoDB入门及 c# .netcore客户端MongoDB.Driver使用

    MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系 ...

  4. centos yum 安装 mongodb 以及php扩展

    centos yum 安装 mongodb 以及php扩展 投稿:hebedich 字体:[增加 减小] 类型:转载 MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用 ...

  5. 基于Mongodb的轻量级领域驱动框架(序)

    混园子也有些年头了,从各个大牛那儿学了很多东西.技术这东西和中国的料理一样,其中技巧和经验,代代相传(这不是舌尖上的中国广告).转身回头一望,几年来自己也积累了一些东西,五花八门涉猎到各种方向,今日开 ...

  6. 基于MongoDB打造.Net的分布式Session子系统

    基于MongoDB打造.Net的分布式Session子系统 Taobao有她自己的分布式session框架,.net阵营也不能落后了,在下做了个基于MongoDB的支持最多26台MongoDB的分布式 ...

  7. 基于MongoDb官方C#驱动封装MongoDbCsharpHelper类(CRUD类)

    近期工作中有使用到 MongoDb作为日志持久化对象,需要实现对MongoDb的增.删.改.查,但由于MongoDb的版本比较新,是2.4以上版本的,网上已有的一些MongoDb Helper类都是基 ...

  8. C# .NET Core 3.1中使用 MongoDB.Driver 更新嵌套数组元素和关联的一些坑

    C# .NET Core 3.1中使用 MongoDB.Driver 更新数组元素和关联的一些坑 前言: 由于工作的原因,使用的数据库由原来的 关系型数据库 MySQL.SQL Server 变成了 ...

  9. 基于Spring的可扩展Schema进行开发自定义配置标签支持

    一.背景 最近和朋友一起想开发一个类似alibaba dubbo的功能的工具,其中就用到了基于Spring的可扩展Schema进行开发自定义配置标签支持,通过上网查资料自己写了一个demo.今天在这里 ...

随机推荐

  1. kv.go

    package clientv3 import (     pb "github.com/coreos/etcd/etcdserver/etcdserverpb" //protob ...

  2. Vert.x 线程模型揭秘

    来源:鸟窝, colobu.com/2016/03/31/vertx-thread-model/ 如有好文章投稿,请点击 → 这里了解详情 Vert.x是一个在JVM开发reactive应用的框架,可 ...

  3. BZOJ_3675_[Apio2014]序列分割_斜率优化

    BZOJ_3675_[Apio2014]序列分割_斜率优化 Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了 ...

  4. Ubuntu18.04美化主题(mac主题)

    前端时间Ubuntu18.04LTS发布,碰巧之前用的Ubuntu16.04出了一点问题,懒得解决,索性就换了Ubuntu18.04. 成果: 参考博客:https://www.cnblogs.com ...

  5. 如何使用命令行编译和运行java文件

    相信大家现在一般都在使用IDE环境来开发运行java文件,但我觉得可以在命令行里面简单运行java文件,技多不压身. 接下来我来说一下编译和运行java文件: 第一步,首先下一个入门程序(注意:一定要 ...

  6. Java 11 新功能来了!

    关键时刻,第一时间送达! 目前 Oracle 已经发布了 Java Development Kit 10,下个版本 JDK 11 也即将发布.本文介绍 Java 11 的新功能. 根据Oracle新出 ...

  7. 【SAP业务模式】之STO(二):系统配置

    本篇博文开始讲述STO业务模式的配置! 一.定义发货工厂的装运数据: 目录:SPRO-物料管理-采购-采购订单-设置库存调拨订单-定义工厂的装运数据 定义发货工厂的装运数据: 为收货工厂分配客户代码: ...

  8. Spark学习之Spark调优与调试(一)

    一.使用SparkConf配置Spark 对 Spark 进行性能调优,通常就是修改 Spark 应用的运行时配置选项.Spark 中最主要的配置机制是通过 SparkConf 类对 Spark 进行 ...

  9. 系统的讲解 - PHP 浮点数高精度运算

    目录 概述 浮点数运算的"锅" 任意精度数学函数 常用数值处理方案 扩展 小结 概述 记录下,工作中遇到的坑 ... 关于 PHP 浮点数运算,特别是金融行业.电子商务订单管理.数 ...

  10. bind、call和apply对比和使用

    最开始关于call.apply.bind函数的使用时,总是很模糊,不知道用哪一个,this指向问题等,看了一些别人的总结后有了一定的理解,所以特地记录一下: 要搞清楚call.apply.bind我们 ...